home *** CD-ROM | disk | FTP | other *** search
/ Stone Design / Stone Design.iso / Stone_Friends / Wave / WavesWorld / Source / IBPalettes / WW3DKit / WW3DCameraShotViz < prev    next >
Encoding:
Text File  |  1995-03-22  |  136.8 KB  |  4,272 lines

  1. // copyright 1993 Michael B. Johnson; some portions copyright 1994, MIT
  2. // see COPYRIGHT for reuse legalities
  3. //
  4.  
  5. /* Copyright 1993 Michael B. Johnson
  6.  * Permission to use, copy, modify, and distribute this
  7.  * software and its documentation for any non-commercial 
  8.  * purpose and without fee is hereby granted, provided that the 
  9.  * above copyright notice appears in all copies.  Michael B. Johnson
  10.  * makes no representations about the suitability of this
  11.  * software for any purpose.  It is provided "as is" without
  12.  * express or implied warranty.
  13.  *
  14.  * Permission to use, copy, modify or distribute this software
  15.  * and its documentation for any commercial purpose must be
  16.  * confirmed in writing with Michael B. Johnson.  He can be
  17.  * contacted at:
  18.  *              20 Ames St. E15-023G    
  19.  *              Cambridge, MA 02141
  20.  *              (617) 547 0563
  21.  *              
  22.  */
  23.  
  24.  
  25. #import "WW3DCamera.h"
  26.  
  27. #import "WWInterp.h" // this includes WWTCLWidgets.h 
  28.  
  29. #import "WW3DShape.h"
  30. #import "WW3DShader.h"
  31. #import "WW3DText.h"
  32. #import "RIBColor.h"
  33. #import "RIBTorus.h"
  34. #import "WW3DLight.h"
  35.  
  36. #import "WW3DWell.h"
  37. #import "WWSceneClock.h"  // has the sceneClock protocol - formalize this!
  38.  
  39. #import <mach/cthreads.h>
  40.  
  41. @implementation WW3DCamera
  42.  
  43. + initialize { return [WW3DCamera setVersion:4], self; }
  44.  
  45. static char errBuf[1024]; 
  46.  
  47. /*
  48. ==========================================================================
  49. subext() -- Remove extension from fname only if it is there.
  50.  
  51. ==========================================================================
  52. */
  53. static char 
  54. *subext(fname, ext)
  55. register char *fname, *ext;
  56. {
  57.   int fl, el;
  58.  
  59.     for ( fl = strlen(fname), el = strlen(ext);
  60.         --el > -1 && --fl > -1 && fname[fl] == ext[el]; )
  61.         ;
  62.     if (el == -1) 
  63.     {  fname[fl] = '\0';
  64.     }
  65.     return(fname);
  66. }
  67.  
  68.  
  69. /*
  70. ==========================================================================
  71. basename() -- deletes any prefix ending in `/' and the suffix.
  72.  
  73. ==========================================================================
  74. */
  75. static char 
  76. *basename(str, sfx, dest)
  77. char *str, *sfx, *dest;
  78. {
  79. char temp[1024];
  80. char *p, *p1;
  81. char *subext();
  82.  
  83.     p = p1 = temp;
  84.     strcpy(p, str);
  85.     while (*p) 
  86.     {  if (*p++ == '/') 
  87.            {  p1 = p;
  88.        }
  89.     }
  90.     strcpy (dest, subext(p1, sfx));
  91.     return(dest);
  92. }
  93.  
  94.  
  95. static int
  96. cmd_dumpRIBToFile(me, interp, argc, argv)
  97. WW3DCamera *me;
  98. Tcl_Interp *interp;
  99. int argc;
  100. char **argv;
  101. {
  102.   char  *my_args = "filename";
  103.   int    num_args = 2;
  104.  
  105.  
  106.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  107.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  108.   if (argc != num_args)
  109.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  110.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  111.      return TCL_ERROR;
  112.   }
  113.  
  114.   [me dumpRIBToFile:argv[1]];
  115.  
  116.   return TCL_OK;
  117. }
  118.  
  119. static int
  120. cmd_display(me, interp, argc, argv)
  121. WW3DCamera *me;
  122. Tcl_Interp *interp;
  123. int argc;
  124. char **argv;
  125. {
  126.   char  *my_args = "";
  127.   int    num_args = 1;
  128.  
  129.  
  130.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  131.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  132.   if (argc != num_args)
  133.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  134.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  135.      return TCL_ERROR;
  136.   }
  137.  
  138.   [me display];
  139.  
  140.   return TCL_OK;
  141. }
  142.  
  143. static int
  144. cmd_backgroundColor(me, interp, argc, argv)
  145. WW3DCamera *me;
  146. Tcl_Interp *interp;
  147. int argc;
  148. char **argv;
  149. {
  150.   char     *my_args = "[{r g b}]";
  151.   NXColor  backgroundColor;
  152.   int      argc2;
  153.   char     **argv2;
  154.   float    red, green, blue;
  155.  
  156.  
  157.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  158.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  159.   if ((argc != 1) && (argc != 2) && (argc != 4))
  160.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  161.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  162.      return TCL_ERROR;
  163.   }
  164.   if (argc == 1)
  165.   {  backgroundColor = [me backgroundColor];
  166.      sprintf(interp->result, "{%f %f %f}", 
  167.          NXRedComponent(backgroundColor), 
  168.          NXGreenComponent(backgroundColor), 
  169.          NXBlueComponent(backgroundColor));
  170.      return TCL_OK;
  171.   }
  172.   if (argc == 2)
  173.   {  Tcl_SplitList(interp, argv[1], &argc2, &argv2);
  174.      if (argc2 != 3)
  175.      {  sprintf(errBuf, "USAGE: %s %s (colors should have 3 components)", argv[0], my_args);
  176.         Tcl_AppendResult(interp, errBuf, (char *)NULL);
  177.         if (argv2) { free(argv2); }
  178.     return TCL_ERROR;
  179.      }
  180.      red = (float)atof(argv2[0]);
  181.      green = (float)atof(argv2[1]);
  182.      blue = (float)atof(argv2[2]);
  183.      free(argv2);
  184.      backgroundColor = NXConvertRGBAToColor(red, green, blue, 1.0);
  185.      [me setBackgroundColor:backgroundColor];
  186.      backgroundColor = [me backgroundColor];
  187.      sprintf(interp->result, "{%f %f %f}", 
  188.          NXRedComponent(backgroundColor), 
  189.          NXGreenComponent(backgroundColor), 
  190.          NXBlueComponent(backgroundColor));
  191.      return TCL_OK;
  192.   }
  193.   if (argc == 4)
  194.   {  red = (float)atof(argv[1]);
  195.      green = (float)atof(argv[2]);
  196.      blue = (float)atof(argv[3]);
  197.      backgroundColor = NXConvertRGBAToColor(red, green, blue, 1.0);
  198.      [me setBackgroundColor:backgroundColor];
  199.      backgroundColor = [me backgroundColor];
  200.      sprintf(interp->result, "{%f %f %f}", 
  201.          NXRedComponent(backgroundColor), 
  202.          NXGreenComponent(backgroundColor), 
  203.          NXBlueComponent(backgroundColor));
  204.      return TCL_OK;
  205.   }
  206.   return TCL_ERROR;
  207. }
  208.  
  209. static int
  210. cmd_fieldOfView(me, interp, argc, argv)
  211. WW3DCamera *me;
  212. Tcl_Interp *interp;
  213. int argc;
  214. char **argv;
  215. {
  216.   char  *my_args = "[fov]";
  217.  
  218.  
  219.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  220.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  221.   if ((argc != 1) && (argc != 2))
  222.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  223.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  224.      return TCL_ERROR;
  225.   }
  226.  
  227.   if (argc == 1)
  228.   {  sprintf(interp->result, "%f", [me fieldOfView]);
  229.      return TCL_OK;
  230.   }
  231.   if (argc == 2)
  232.   {  [me setFieldOfViewByAngle:(float)atof(argv[1])];
  233.      sprintf(interp->result, "%f", [me fieldOfView]);
  234.      return TCL_OK;
  235.   }
  236.   return TCL_ERROR;
  237. }
  238.  
  239. static int
  240. cmd_setEyeAtTowardRoll(me, interp, argc, argv)
  241. WW3DCamera *me;
  242. Tcl_Interp *interp;
  243. int argc;
  244. char **argv;
  245. {
  246.   char     *my_args = "fromPoint toPoint aRollAngle";
  247.   int       num_args = 4, argc2;
  248.   RtPoint  fromPoint, toPoint;
  249.   float    aRollAngle;
  250.   char     **argv2;
  251.  
  252.  
  253.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  254.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  255.   if (argc != num_args)
  256.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  257.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  258.      return TCL_ERROR;
  259.   }
  260.  
  261.   Tcl_SplitList(interp, argv[1], &argc2, &argv2); // fromPoint
  262.   if (argc2 != 3)
  263.   {  sprintf(errBuf, "USAGE: %s %s (points should have 3 components)", argv[0], my_args);
  264.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  265.      if (argv2) { free(argv2); }
  266.      return TCL_ERROR;
  267.   }
  268.   N3D_XComp(fromPoint) = (float)atof(argv2[0]);
  269.   N3D_YComp(fromPoint) = (float)atof(argv2[1]);
  270.   N3D_ZComp(fromPoint) = (float)atof(argv2[2]);
  271.   free(argv2);
  272.  
  273.   Tcl_SplitList(interp, argv[2], &argc2, &argv2); // fromPoint
  274.   if (argc2 != 3)
  275.   {  sprintf(errBuf, "USAGE: %s %s (points should have 3 components)", argv[0], my_args);
  276.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  277.      if (argv2) { free(argv2); }
  278.      return TCL_ERROR;
  279.   }
  280.   N3D_XComp(toPoint) = (float)atof(argv2[0]);
  281.   N3D_YComp(toPoint) = (float)atof(argv2[1]);
  282.   N3D_ZComp(toPoint) = (float)atof(argv2[2]);
  283.   free(argv2);
  284.  
  285.   aRollAngle = (float)atof(argv[3]);
  286.  
  287.   [me setEyeAt:fromPoint toward:toPoint roll:aRollAngle];
  288.  
  289.   return TCL_OK;
  290. }
  291.  
  292. static int
  293. cmd_moveEyeBy(me, interp, argc, argv)
  294. WW3DCamera *me;
  295. Tcl_Interp *interp;
  296. int argc;
  297. char **argv;
  298. {
  299.   char  *my_args = "sDistance tDistance uDistance";
  300.   int    num_args = 4;
  301.  
  302.  
  303.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  304.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  305.   if (argc != num_args)
  306.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  307.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  308.      return TCL_ERROR;
  309.   }
  310.  
  311.   [me moveEyeBy:(float)atof(argv[1]) :(float)atof(argv[2]) :(float)atof(argv[3])]; 
  312.   //[[me delegate] cameraParametersWereUpdated:me];
  313.   return TCL_OK;
  314. }
  315.  
  316. static int
  317. cmd_getEyePoint(me, interp, argc, argv)
  318. WW3DCamera *me;
  319. Tcl_Interp *interp;
  320. int argc;
  321. char **argv;
  322. {
  323.   char     *my_args = "";
  324.   int       num_args = 1;
  325.   RtPoint  eyePoint, viewPoint;
  326.   float    aRollAngle;
  327.  
  328.  
  329.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  330.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  331.   if (argc != num_args)
  332.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  333.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  334.      return TCL_ERROR;
  335.   }
  336.  
  337.   [me getEyeAt:&eyePoint toward:&viewPoint roll:&aRollAngle];
  338.   sprintf(interp->result, 
  339.       "%f %f %f", 
  340.       N3D_XComp(eyePoint), N3D_YComp(eyePoint), N3D_ZComp(eyePoint));
  341.   return TCL_OK;
  342. }
  343.  
  344. static int
  345. cmd_getViewPoint(me, interp, argc, argv)
  346. WW3DCamera *me;
  347. Tcl_Interp *interp;
  348. int argc;
  349. char **argv;
  350. {
  351.   char     *my_args = "";
  352.   int       num_args = 1;
  353.   RtPoint  eyePoint, viewPoint;
  354.   float    aRollAngle;
  355.  
  356.  
  357.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  358.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  359.   if (argc != num_args)
  360.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  361.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  362.      return TCL_ERROR;
  363.   }
  364.  
  365.   [me getEyeAt:&eyePoint toward:&viewPoint roll:&aRollAngle];
  366.   sprintf(interp->result, 
  367.       "%f %f %f", 
  368.       N3D_XComp(viewPoint), N3D_YComp(viewPoint), N3D_ZComp(viewPoint));
  369.   return TCL_OK;
  370. }
  371.  
  372. static int
  373. cmd_getRollAngle(me, interp, argc, argv)
  374. WW3DCamera *me;
  375. Tcl_Interp *interp;
  376. int argc;
  377. char **argv;
  378. {
  379.   char     *my_args = "";
  380.   int       num_args = 1;
  381.   RtPoint  eyePoint, viewPoint;
  382.   float    aRollAngle;
  383.  
  384.  
  385.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  386.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  387.   if (argc != num_args)
  388.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  389.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  390.      return TCL_ERROR;
  391.   }
  392.  
  393.   [me getEyeAt:&eyePoint toward:&viewPoint roll:&aRollAngle];
  394.   sprintf(interp->result, "%f", aRollAngle);
  395.   return TCL_OK;
  396. }
  397.  
  398. static int
  399. cmd_getEyeAtTowardRoll(me, interp, argc, argv)
  400. WW3DCamera *me;
  401. Tcl_Interp *interp;
  402. int argc;
  403. char **argv;
  404. {
  405.   char     *my_args = "";
  406.   int       num_args = 1;
  407.   RtPoint  eyePoint, viewPoint;
  408.   float    aRollAngle;
  409.  
  410.  
  411.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  412.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  413.   if (argc != num_args)
  414.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  415.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  416.      return TCL_ERROR;
  417.   }
  418.  
  419.   [me getEyeAt:&eyePoint toward:&viewPoint roll:&aRollAngle];
  420.   sprintf(interp->result, 
  421.       "{%f %f %f} {%f %f %f} %f", 
  422.       N3D_XComp(eyePoint), N3D_YComp(eyePoint), N3D_ZComp(eyePoint),
  423.       N3D_XComp(viewPoint), N3D_YComp(viewPoint), N3D_ZComp(viewPoint),
  424.       aRollAngle);
  425.   return TCL_OK;
  426. }
  427.  
  428. static int
  429. cmd_setSurfaceTypeForAll(me, interp, argc, argv)
  430. WW3DCamera *me;
  431. Tcl_Interp *interp;
  432. int argc;
  433. char **argv;
  434. {
  435.   char  *my_args = "PointCloud|WireFrame|ShadedWireFrame|FacetedSolids|SmoothSolids";
  436.   int    num_args = 2;
  437.  
  438.  
  439.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  440.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  441.   if (argc != num_args)
  442.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  443.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  444.      return TCL_ERROR;
  445.   }
  446.  
  447.   if (!strcmp(argv[1], "PointCloud"))
  448.   {  [me setSurfaceTypeForAll:N3D_PointCloud chooseHider:YES];
  449.      //[[me delegate] cameraParametersWereUpdated:me];
  450.      return TCL_OK;
  451.   }
  452.   if (!strcmp(argv[1], "WireFrame"))
  453.   {  [me setSurfaceTypeForAll:N3D_WireFrame chooseHider:YES];
  454.      //[[me delegate] cameraParametersWereUpdated:me];
  455.      return TCL_OK;
  456.   }
  457.   if (!strcmp(argv[1], "ShadedWireFrame"))
  458.   {  [me setSurfaceTypeForAll:N3D_ShadedWireFrame chooseHider:YES];
  459.      //[[me delegate] cameraParametersWereUpdated:me];
  460.      return TCL_OK;
  461.   }
  462.   if (!strcmp(argv[1], "FacetedSolids"))
  463.   {  [me setSurfaceTypeForAll:N3D_FacetedSolids chooseHider:YES];
  464.      //[[me delegate] cameraParametersWereUpdated:me];
  465.      return TCL_OK;
  466.   }
  467.   if (!strcmp(argv[1], "SmoothSolids"))
  468.   {  [me setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES];
  469.      //[[me delegate] cameraParametersWereUpdated:me];
  470.      return TCL_OK;
  471.   }
  472.  
  473.   sprintf(errBuf, "ERROR: unknown surface type <%s>\nUSAGE: %s %s", argv[1], argv[0], my_args);
  474.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  475.   return TCL_ERROR;
  476. }
  477.  
  478.  
  479. static int
  480. cmd_removeDefaultLights(me, interp, argc, argv)
  481. WW3DCamera *me;
  482. Tcl_Interp *interp;
  483. int argc;
  484. char **argv;
  485. {
  486.   char  *my_args = "";
  487.   int    num_args = 1;
  488.  
  489.  
  490.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  491.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  492.   if (argc != num_args)
  493.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  494.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  495.      return TCL_ERROR;
  496.   }
  497.  
  498.   [me removeDefaultLights];
  499.   //[[me delegate] cameraParametersWereUpdated:me];
  500.  
  501.   return TCL_OK;
  502. }
  503.  
  504. static int
  505. cmd_restoreDefaultLights(me, interp, argc, argv)
  506. WW3DCamera *me;
  507. Tcl_Interp *interp;
  508. int argc;
  509. char **argv;
  510. {
  511.   char  *my_args = "";
  512.   int    num_args = 1;
  513.  
  514.  
  515.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  516.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  517.   if (argc != num_args)
  518.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  519.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  520.      return TCL_ERROR;
  521.   }
  522.  
  523.   [me restoreDefaultLights];
  524.   //[[me delegate] cameraParametersWereUpdated:me];
  525.  
  526.   return TCL_OK;
  527. }
  528.  
  529. static int
  530. cmd_lightList(me, interp, argc, argv)
  531. WW3DCamera *me;
  532. Tcl_Interp *interp;
  533. int argc;
  534. char **argv;
  535. {
  536.   char          *my_args = "";
  537.   int            num_args = 1, i;
  538.   id            theLightList;
  539.   N3DLight      *light;
  540.   N3DLightType  lightType;
  541.   char          aBuf[MAXPATHLEN];
  542.   RtPoint       from, to;
  543.   RtFloat       coneAngle, coneDelta, beamDistribution;
  544.   NXColor       color;
  545.  
  546.  
  547.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  548.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  549.   if (argc != num_args)
  550.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  551.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  552.      return TCL_ERROR;
  553.   }
  554.   theLightList = [me lightList];
  555.   
  556.   Tcl_AppendResult(interp, "{", (char *)NULL);
  557.   for (i = 0; i < [theLightList count]; i++)
  558.   {  light = [theLightList objectAt:i];
  559.      Tcl_AppendResult(interp, "{", (char *)NULL);
  560.  
  561.      sprintf(aBuf, "name %s", [light shapeName]);
  562.      Tcl_AppendElement(interp, aBuf);
  563.  
  564.      lightType = [light type];
  565.      switch (lightType)  
  566.      {  case N3D_AmbientLight:  Tcl_AppendElement(interp, "type ambient");
  567.                             break;
  568.         case N3D_PointLight:    Tcl_AppendElement(interp, "type point");
  569.                             break;
  570.         case N3D_DistantLight:  Tcl_AppendElement(interp, "type distant");
  571.                             break;
  572.         case N3D_SpotLight:     Tcl_AppendElement(interp, "type spot");
  573.                             break;
  574.         default:                Tcl_AppendElement(interp, "type unknown");
  575.                             break;
  576.      }
  577.  
  578.      [light getFrom:&from to:&to];
  579.      sprintf(aBuf, "from %f %f %f", from[0], from[1], from[2]);
  580.      Tcl_AppendElement(interp, aBuf);
  581.      sprintf(aBuf, "to %f %f %f", to[0], to[1], to[2]);
  582.      Tcl_AppendElement(interp, aBuf);
  583.  
  584.      sprintf(aBuf, "intensity %f", [light intensity]);
  585.      Tcl_AppendElement(interp, aBuf);
  586.  
  587.      [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  588.      sprintf(aBuf, "coneAngle %f", coneAngle);
  589.      Tcl_AppendElement(interp, aBuf);
  590.      sprintf(aBuf, "coneDelta %f", coneDelta);
  591.      Tcl_AppendElement(interp, aBuf);
  592.      sprintf(aBuf, "beamDistribution %f", beamDistribution);
  593.      Tcl_AppendElement(interp, aBuf);
  594.  
  595.      color = [light color];
  596.      sprintf(aBuf, "color %f %f %f", 
  597.          NXRedComponent(color), NXGreenComponent(color), NXBlueComponent(color));
  598.      Tcl_AppendElement(interp, aBuf);
  599.  
  600.      sprintf(aBuf, "isGlobal %d", (int)[light isGlobal]);
  601.      Tcl_AppendElement(interp, aBuf);
  602.  
  603.      Tcl_AppendResult(interp, "}", (char *)NULL);
  604.   }
  605.   Tcl_AppendResult(interp, "}", (char *)NULL);
  606.   return TCL_OK;
  607. }
  608.  
  609.  
  610. static int
  611. cmd_otherLightList(me, interp, argc, argv)
  612. WW3DCamera *me;
  613. Tcl_Interp *interp;
  614. int argc;
  615. char **argv;
  616. {
  617.   char          *my_args = "";
  618.   int            num_args = 1, i;
  619.   id            theLightList;
  620.   N3DLight      *light;
  621.   N3DLightType  lightType;
  622.   char          aBuf[MAXPATHLEN];
  623.   RtPoint       from, to;
  624.   RtFloat       coneAngle, coneDelta, beamDistribution;
  625.   NXColor       color;
  626.  
  627.  
  628.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  629.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  630.   if (argc != num_args)
  631.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  632.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  633.      return TCL_ERROR;
  634.   }
  635.   theLightList = [me otherLightList];
  636.   
  637.   Tcl_AppendResult(interp, "{", (char *)NULL);
  638.   for (i = 0; i < [theLightList count]; i++)
  639.   {  light = [theLightList objectAt:i];
  640.      Tcl_AppendResult(interp, "{", (char *)NULL);
  641.  
  642.      sprintf(aBuf, "name %s", [light shapeName]);
  643.      Tcl_AppendElement(interp, aBuf);
  644.  
  645.      lightType = [light type];
  646.      switch (lightType)  
  647.      {  case N3D_AmbientLight:  Tcl_AppendElement(interp, "type ambient");
  648.                             break;
  649.         case N3D_PointLight:    Tcl_AppendElement(interp, "type point");
  650.                             break;
  651.         case N3D_DistantLight:  Tcl_AppendElement(interp, "type distant");
  652.                             break;
  653.         case N3D_SpotLight:     Tcl_AppendElement(interp, "type spot");
  654.                             break;
  655.         default:                Tcl_AppendElement(interp, "type unknown");
  656.                             break;
  657.      }
  658.  
  659.      [light getFrom:&from to:&to];
  660.      sprintf(aBuf, "from %f %f %f", from[0], from[1], from[2]);
  661.      Tcl_AppendElement(interp, aBuf);
  662.      sprintf(aBuf, "to %f %f %f", to[0], to[1], to[2]);
  663.      Tcl_AppendElement(interp, aBuf);
  664.  
  665.      sprintf(aBuf, "intensity %f", [light intensity]);
  666.      Tcl_AppendElement(interp, aBuf);
  667.  
  668.      [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  669.      sprintf(aBuf, "coneAngle %f", coneAngle);
  670.      Tcl_AppendElement(interp, aBuf);
  671.      sprintf(aBuf, "coneDelta %f", coneDelta);
  672.      Tcl_AppendElement(interp, aBuf);
  673.      sprintf(aBuf, "beamDistribution %f", beamDistribution);
  674.      Tcl_AppendElement(interp, aBuf);
  675.  
  676.      color = [light color];
  677.      sprintf(aBuf, "color %f %f %f", 
  678.          NXRedComponent(color), NXGreenComponent(color), NXBlueComponent(color));
  679.      Tcl_AppendElement(interp, aBuf);
  680.  
  681.      sprintf(aBuf, "isGlobal %d", (int)[light isGlobal]);
  682.      Tcl_AppendElement(interp, aBuf);
  683.  
  684.      Tcl_AppendResult(interp, "}", (char *)NULL);
  685.   }
  686.   Tcl_AppendResult(interp, "}", (char *)NULL);
  687.   return TCL_OK;
  688. }
  689.  
  690.  
  691. static int
  692. cmd_addAmbientLight(me, interp, argc, argv)
  693. WW3DCamera *me;
  694. Tcl_Interp *interp;
  695. int argc;
  696. char **argv;
  697. {
  698.   char       *my_args = "name intensity [pathToParent]";
  699.   int         num_args = 3;
  700.   WW3DLight  *light;
  701.  
  702.  
  703.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  704.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  705.   if ((argc != num_args) && (argc != (num_args+1)))
  706.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  707.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  708.      return TCL_ERROR;
  709.   }
  710.   light = [[[WW3DLight alloc] init] makeAmbientWithIntensity:(RtFloat)atof(argv[2])];
  711.   [light setShapeName:argv[1]];
  712.   if (argc == (num_args + 1)) // local, visible light
  713.   {  if (![me addLocalLight:light usingPath:argv[num_args]])
  714.      {  sprintf(errBuf, "unable to add local ambient light %s as a child of shape %s", argv[1], argv[num_args]); 
  715.         Tcl_AppendResult(interp, errBuf, (char *)NULL);
  716.         return TCL_ERROR;
  717.      }
  718.   }
  719.   else  // regular global light
  720.   {  [me addLight:light];
  721.   }
  722.   return TCL_OK;
  723. }
  724.  
  725.  
  726. static int
  727. cmd_addPointLight(me, interp, argc, argv)
  728. WW3DCamera *me;
  729. Tcl_Interp *interp;
  730. int argc;
  731. char **argv;
  732. {
  733.   char       *my_args = "name fromX fromY fromZ intensity [pathToParent]";
  734.   int         num_args = 6;
  735.   RtPoint    from;
  736.   WW3DLight  *light;
  737.  
  738.  
  739.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  740.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  741.   if ((argc != num_args) && (argc != (num_args+1)))
  742.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  743.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  744.      return TCL_ERROR;
  745.   }
  746.   from[0] = (RtFloat)atof(argv[2]);
  747.   from[1] = (RtFloat)atof(argv[3]);
  748.   from[2] = (RtFloat)atof(argv[4]);
  749.   light = [[[WW3DLight alloc] init] makePointFrom:from intensity:(RtFloat)atof(argv[4])];
  750.   [light setShapeName:argv[1]];
  751.   if (argc == (num_args + 1)) // local, visible light
  752.   {  if (![me addLocalLight:light usingPath:argv[num_args]])
  753.      {  sprintf(errBuf, "unable to add local point light %s as a child of shape %s", argv[1], argv[num_args]); 
  754.         Tcl_AppendResult(interp, errBuf, (char *)NULL);
  755.         return TCL_ERROR;
  756.      }
  757.   }
  758.   else  // regular global light
  759.   {  [me addLight:light];
  760.   }
  761.  
  762.   return TCL_OK;
  763. }
  764.  
  765.  
  766. static int
  767. cmd_addDistantLight(me, interp, argc, argv)
  768. WW3DCamera *me;
  769. Tcl_Interp *interp;
  770. int argc;
  771. char **argv;
  772. {
  773.   char       *my_args = "name fromX fromY fromZ toX toY toZ intensity [pathToParent]";
  774.   int         num_args = 9;
  775.   RtPoint    from, to;
  776.   WW3DLight  *light;
  777.  
  778.  
  779.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  780.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  781.   if ((argc != num_args) && (argc != (num_args+1)))
  782.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  783.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  784.      return TCL_ERROR;
  785.   }
  786.   from[0] = (RtFloat)atof(argv[2]);
  787.   from[1] = (RtFloat)atof(argv[3]);
  788.   from[2] = (RtFloat)atof(argv[4]);
  789.   to[0] = (RtFloat)atof(argv[5]);
  790.   to[1] = (RtFloat)atof(argv[6]);
  791.   to[2] = (RtFloat)atof(argv[7]);
  792.   light = [[[WW3DLight alloc] init] makeDistantFrom:from to:to intensity:(RtFloat)atof(argv[8])];
  793.   [light setShapeName:argv[1]];
  794.   if (argc == (num_args + 1)) // local, visible light
  795.   {  if (![me addLocalLight:light usingPath:argv[num_args]])
  796.      {  sprintf(errBuf, "unable to add local distant light %s as a child of shape %s", argv[1], argv[num_args]); 
  797.         Tcl_AppendResult(interp, errBuf, (char *)NULL);
  798.         return TCL_ERROR;
  799.      }
  800.   }
  801.   else  // regular global light
  802.   {  [me addLight:light];
  803.   }
  804.  
  805.   return TCL_OK;
  806. }
  807.  
  808.  
  809. static int
  810. cmd_addSpotLight(me, interp, argc, argv)
  811. WW3DCamera *me;
  812. Tcl_Interp *interp;
  813. int argc;
  814. char **argv;
  815. {
  816.   char       *my_args = "name fromX fromY fromZ toX toY toZ coneAngle coneDelta beamDistribution intensity [pathToParent]";
  817.   int         num_args = 12;
  818.   RtPoint    from, to;
  819.   WW3DLight  *light;
  820.  
  821.  
  822.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  823.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  824.   if ((argc != num_args) && (argc != (num_args+1)))
  825.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  826.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  827.      return TCL_ERROR;
  828.   }
  829.   from[0] = (RtFloat)atof(argv[2]);
  830.   from[1] = (RtFloat)atof(argv[3]);
  831.   from[2] = (RtFloat)atof(argv[4]);
  832.   to[0] = (RtFloat)atof(argv[5]);
  833.   to[1] = (RtFloat)atof(argv[6]);
  834.   to[2] = (RtFloat)atof(argv[7]);
  835.   light = [[[WW3DLight alloc] init] makeSpotFrom:from to:to 
  836.                                          coneAngle:(RtFloat)atof(argv[8]) 
  837.                                         coneDelta:(RtFloat)atof(argv[9]) 
  838.                                         beamDistribution:(RtFloat)atof(argv[10]) 
  839.                                         intensity:(RtFloat)atof(argv[11])];
  840.   [light setShapeName:argv[1]];
  841.   if (argc == (num_args + 1)) // local, visible light
  842.   {  if (![me addLocalLight:light usingPath:argv[num_args]])
  843.      {  sprintf(errBuf, "unable to add local point light %s as a child of shape %s", argv[1], argv[num_args]); 
  844.         Tcl_AppendResult(interp, errBuf, (char *)NULL);
  845.         return TCL_ERROR;
  846.      }
  847.   }
  848.   else  // regular global light
  849.   {  [me addLight:light];
  850.   }
  851.  
  852.   return TCL_OK;
  853. }
  854.  
  855.  
  856. static int
  857. cmd_setLightIntensity(me, interp, argc, argv)
  858. WW3DCamera *me;
  859. Tcl_Interp *interp;
  860. int argc;
  861. char **argv;
  862. {
  863.   char       *my_args = "name intensity";
  864.   int         num_args = 3, i;
  865.   WW3DLight  *light;
  866.   id         lightList = [me lightList];
  867.   id         otherLightList = [me otherLightList];
  868.  
  869.  
  870.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  871.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  872.   if (argc != num_args)
  873.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  874.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  875.      return TCL_ERROR;
  876.   }
  877.   
  878.   for (i = 0; i < [lightList count]; i++)
  879.   {  light = [lightList objectAt:i];
  880.      if (!strcmp(argv[1], [light shapeName]))
  881.      {  [light setIntensity:(RtFloat)atof(argv[2])];
  882.         return TCL_OK;
  883.      }
  884.   }
  885.  
  886.   for (i = 0; i < [otherLightList count]; i++)
  887.   {  light = [otherLightList objectAt:i];
  888.      if (!strcmp(argv[1], [light shapeName]))
  889.      {  [light setIntensity:(RtFloat)atof(argv[2])];
  890.         return TCL_OK;
  891.      }
  892.   }
  893.  
  894.   sprintf(errBuf, "no light named %s - unable to set intensity...", argv[1]);
  895.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  896.   return TCL_ERROR;
  897. }
  898.  
  899.  
  900. static int
  901. cmd_setLightType(me, interp, argc, argv)
  902. WW3DCamera *me;
  903. Tcl_Interp *interp;
  904. int argc;
  905. char **argv;
  906. {
  907.   char          *my_args = "name type";
  908.   int            num_args = 3, i;
  909.   WW3DLight     *light;
  910.   id            lightList = [me lightList];
  911.   id         otherLightList = [me otherLightList];
  912.   N3DLightType  lightType = N3D_AmbientLight;
  913.   BOOL          validLightType = NO;
  914.  
  915.  
  916.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  917.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  918.   if (argc != num_args)
  919.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  920.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  921.      return TCL_ERROR;
  922.   }
  923.  
  924.   if (!strcmp(argv[2], "ambient"))
  925.   {  lightType = N3D_AmbientLight;
  926.      validLightType = YES;
  927.   }
  928.   if (!strcmp(argv[2], "point"))
  929.   {  lightType = N3D_PointLight;
  930.      validLightType = YES;
  931.   }
  932.   if (!strcmp(argv[2], "distant"))
  933.   {  lightType = N3D_DistantLight;
  934.      validLightType = YES;
  935.   }
  936.   if (!strcmp(argv[2], "spot"))
  937.   {  lightType = N3D_SpotLight;
  938.      validLightType = YES;
  939.   }
  940.   if (!validLightType)
  941.   {  sprintf(errBuf, "%s is not a valid light type (ambient|point|distant|spot)", argv[2]);
  942.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  943.      return TCL_ERROR;
  944.   }
  945.  
  946.   for (i = 0; i < [lightList count]; i++)
  947.   {  light = [lightList objectAt:i];
  948.      if (!strcmp(argv[1], [light shapeName]))
  949.      {  [light setType:lightType];
  950.         return TCL_OK;
  951.      }
  952.   }
  953.  
  954.   for (i = 0; i < [otherLightList count]; i++)
  955.   {  light = [otherLightList objectAt:i];
  956.      if (!strcmp(argv[1], [light shapeName]))
  957.      {  [light setType:lightType];
  958.         return TCL_OK;
  959.      }
  960.   }
  961.  
  962.   sprintf(errBuf, "no light named %s - unable to set type...", argv[1]);
  963.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  964.   return TCL_ERROR;
  965. }
  966.  
  967.  
  968. static int
  969. cmd_setLightFrom(me, interp, argc, argv)
  970. WW3DCamera *me;
  971. Tcl_Interp *interp;
  972. int argc;
  973. char **argv;
  974. {
  975.   char       *my_args = "name fromX fromY fromZ";
  976.   int         num_args = 5, i;
  977.   RtPoint    from;
  978.   WW3DLight  *light;
  979.   id         lightList = [me lightList];
  980.   id         otherLightList = [me otherLightList];
  981.  
  982.  
  983.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  984.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  985.   if (argc != num_args)
  986.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  987.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  988.      return TCL_ERROR;
  989.   }
  990.   from[0] = (RtFloat)atof(argv[2]);
  991.   from[1] = (RtFloat)atof(argv[3]);
  992.   from[2] = (RtFloat)atof(argv[4]);
  993.  
  994.   for (i = 0; i < [lightList count]; i++)
  995.   {  light = [lightList objectAt:i];
  996.      if (!strcmp(argv[1], [light shapeName]))
  997.      {  [light setFrom:from];
  998.         return TCL_OK;
  999.      }
  1000.   }
  1001.   for (i = 0; i < [otherLightList count]; i++)
  1002.   {  light = [otherLightList objectAt:i];
  1003.      if (!strcmp(argv[1], [light shapeName]))
  1004.      {  [light setFrom:from];
  1005.         return TCL_OK;
  1006.      }
  1007.   }
  1008.  
  1009.   sprintf(errBuf, "no light named %s - unable to set from point...", argv[1]);
  1010.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1011.   return TCL_ERROR;
  1012. }
  1013.  
  1014.  
  1015. static int
  1016. cmd_setLightTo(me, interp, argc, argv)
  1017. WW3DCamera *me;
  1018. Tcl_Interp *interp;
  1019. int argc;
  1020. char **argv;
  1021. {
  1022.   char       *my_args = "name toX toY toZ";
  1023.   int         num_args = 5, i;
  1024.   RtPoint    from, to;
  1025.   WW3DLight  *light;
  1026.   id         lightList = [me lightList];
  1027.   id         otherLightList = [me otherLightList];
  1028.  
  1029.  
  1030.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1031.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1032.   if (argc != num_args)
  1033.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1034.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1035.      return TCL_ERROR;
  1036.   }
  1037.  
  1038.   for (i = 0; i < [lightList count]; i++)
  1039.   {  light = [lightList objectAt:i];
  1040.      if (!strcmp(argv[1], [light shapeName]))
  1041.      {  [light getFrom:&from to:&to];
  1042.         to[0] = (RtFloat)atof(argv[2]);
  1043.         to[1] = (RtFloat)atof(argv[3]);
  1044.         to[2] = (RtFloat)atof(argv[4]);
  1045.         [light setFrom:from to:to];
  1046.         return TCL_OK;
  1047.      }
  1048.   }
  1049.  
  1050.   for (i = 0; i < [otherLightList count]; i++)
  1051.   {  light = [otherLightList objectAt:i];
  1052.      if (!strcmp(argv[1], [light shapeName]))
  1053.      {  [light getFrom:&from to:&to];
  1054.         to[0] = (RtFloat)atof(argv[2]);
  1055.         to[1] = (RtFloat)atof(argv[3]);
  1056.         to[2] = (RtFloat)atof(argv[4]);
  1057.         [light setFrom:from to:to];
  1058.         return TCL_OK;
  1059.      }
  1060.   }
  1061.  
  1062.   sprintf(errBuf, "no light named %s - unable to set to point...", argv[1]);
  1063.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1064.   return TCL_ERROR;
  1065. }
  1066.  
  1067.  
  1068. static int
  1069. cmd_setLightColor(me, interp, argc, argv)
  1070. WW3DCamera *me;
  1071. Tcl_Interp *interp;
  1072. int argc;
  1073. char **argv;
  1074. {
  1075.   char       *my_args = "name r g b";
  1076.   int         num_args = 5, i;
  1077.   NXColor    color;
  1078.   WW3DLight  *light;
  1079.   id         lightList = [me lightList];
  1080.   id         otherLightList = [me otherLightList];
  1081.  
  1082.  
  1083.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1084.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1085.   if (argc != num_args)
  1086.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1087.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1088.      return TCL_ERROR;
  1089.   }
  1090.   color = NXConvertRGBToColor((float)atof(argv[2]), (float)atof(argv[3]), (float)atof(argv[4]));
  1091.   for (i = 0; i < [lightList count]; i++)
  1092.   {  light = [lightList objectAt:i];
  1093.      if (!strcmp(argv[1], [light shapeName]))
  1094.      {  [light setColor:color];
  1095.         return TCL_OK;
  1096.      }
  1097.   }
  1098.  
  1099.   for (i = 0; i < [otherLightList count]; i++)
  1100.   {  light = [otherLightList objectAt:i];
  1101.      if (!strcmp(argv[1], [light shapeName]))
  1102.      {  [light setColor:color];
  1103.         return TCL_OK;
  1104.      }
  1105.   }
  1106.  
  1107.   sprintf(errBuf, "no light named %s - unable to set color...", argv[1]);
  1108.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1109.   return TCL_ERROR;
  1110. }
  1111.  
  1112.  
  1113. static int
  1114. cmd_setLightConeAngleConeDeltaBeamDistribution(me, interp, argc, argv)
  1115. WW3DCamera *me;
  1116. Tcl_Interp *interp;
  1117. int argc;
  1118. char **argv;
  1119. {
  1120.   char       *my_args = "name coneAngle coneDelta beamDistribution";
  1121.   int         num_args = 5, i;
  1122.   RtFloat    coneAngle, coneDelta, beamDistribution;
  1123.   WW3DLight  *light;
  1124.   id         lightList = [me lightList];
  1125.   id         otherLightList = [me otherLightList];
  1126.  
  1127.  
  1128.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1129.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1130.   if (argc != num_args)
  1131.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1132.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1133.      return TCL_ERROR;
  1134.   }
  1135.   
  1136.   for (i = 0; i < [lightList count]; i++)
  1137.   {  light = [lightList objectAt:i];
  1138.      if (!strcmp(argv[1], [light shapeName]))
  1139.      {  coneAngle = (RtFloat)atof(argv[2]);
  1140.         coneDelta = (RtFloat)atof(argv[3]);
  1141.         beamDistribution = (RtFloat)atof(argv[4]);
  1142.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1143.         return TCL_OK;
  1144.      }
  1145.   }
  1146.  
  1147.   for (i = 0; i < [otherLightList count]; i++)
  1148.   {  light = [otherLightList objectAt:i];
  1149.      if (!strcmp(argv[1], [light shapeName]))
  1150.      {  coneAngle = (RtFloat)atof(argv[2]);
  1151.         coneDelta = (RtFloat)atof(argv[3]);
  1152.         beamDistribution = (RtFloat)atof(argv[4]);
  1153.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1154.         return TCL_OK;
  1155.      }
  1156.   }
  1157.  
  1158.   sprintf(errBuf, "no light named %s - unable to set coneAngle, coneDelta, beamDistribution...", argv[1]);
  1159.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1160.   return TCL_ERROR;
  1161. }
  1162.  
  1163.  
  1164. static int
  1165. cmd_setLightConeAngle(me, interp, argc, argv)
  1166. WW3DCamera *me;
  1167. Tcl_Interp *interp;
  1168. int argc;
  1169. char **argv;
  1170. {
  1171.   char       *my_args = "name coneAngle";
  1172.   int         num_args = 3, i;
  1173.   RtFloat    coneAngle, coneDelta, beamDistribution;
  1174.   WW3DLight  *light;
  1175.   id         lightList = [me lightList];
  1176.   id         otherLightList = [me otherLightList];
  1177.  
  1178.  
  1179.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1180.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1181.   if (argc != num_args)
  1182.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1183.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1184.      return TCL_ERROR;
  1185.   }
  1186.   
  1187.   for (i = 0; i < [lightList count]; i++)
  1188.   {  light = [lightList objectAt:i];
  1189.      if (!strcmp(argv[1], [light shapeName]))
  1190.      {  [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  1191.         coneAngle = (RtFloat)atof(argv[2]);
  1192.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1193.         return TCL_OK;
  1194.      }
  1195.   }
  1196.  
  1197.   for (i = 0; i < [otherLightList count]; i++)
  1198.   {  light = [otherLightList objectAt:i];
  1199.      if (!strcmp(argv[1], [light shapeName]))
  1200.      {  [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  1201.         coneAngle = (RtFloat)atof(argv[2]);
  1202.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1203.         return TCL_OK;
  1204.      }
  1205.   }
  1206.  
  1207.   sprintf(errBuf, "no light named %s - unable to set coneAngle...", argv[1]);
  1208.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1209.   return TCL_ERROR;
  1210. }
  1211.  
  1212.  
  1213. static int
  1214. cmd_setLightConeDelta(me, interp, argc, argv)
  1215. WW3DCamera *me;
  1216. Tcl_Interp *interp;
  1217. int argc;
  1218. char **argv;
  1219. {
  1220.   char       *my_args = "name coneDelta";
  1221.   int         num_args = 3, i;
  1222.   RtFloat    coneAngle, coneDelta, beamDistribution;
  1223.   WW3DLight  *light;
  1224.   id         lightList = [me lightList];
  1225.   id         otherLightList = [me otherLightList];
  1226.  
  1227.  
  1228.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1229.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1230.   if (argc != num_args)
  1231.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1232.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1233.      return TCL_ERROR;
  1234.   }
  1235.   
  1236.   for (i = 0; i < [lightList count]; i++)
  1237.   {  light = [lightList objectAt:i];
  1238.      if (!strcmp(argv[1], [light shapeName]))
  1239.      {  [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  1240.         coneDelta = (RtFloat)atof(argv[2]);
  1241.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1242.         return TCL_OK;
  1243.      }
  1244.   }
  1245.  
  1246.   for (i = 0; i < [otherLightList count]; i++)
  1247.   {  light = [otherLightList objectAt:i];
  1248.      if (!strcmp(argv[1], [light shapeName]))
  1249.      {  [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  1250.         coneDelta = (RtFloat)atof(argv[2]);
  1251.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1252.         return TCL_OK;
  1253.      }
  1254.   }
  1255.  
  1256.   sprintf(errBuf, "no light named %s - unable to set coneDelta...", argv[1]);
  1257.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1258.   return TCL_ERROR;
  1259. }
  1260.  
  1261.  
  1262. static int
  1263. cmd_setLightBeamDistribution(me, interp, argc, argv)
  1264. WW3DCamera *me;
  1265. Tcl_Interp *interp;
  1266. int argc;
  1267. char **argv;
  1268. {
  1269.   char       *my_args = "name beamDistribution";
  1270.   int         num_args = 3, i;
  1271.   RtFloat    coneAngle, coneDelta, beamDistribution;
  1272.   WW3DLight  *light;
  1273.   id         lightList = [me lightList];
  1274.   id         otherLightList = [me otherLightList];
  1275.  
  1276.  
  1277.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1278.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1279.   if (argc != num_args)
  1280.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1281.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1282.      return TCL_ERROR;
  1283.   }
  1284.   
  1285.   for (i = 0; i < [lightList count]; i++)
  1286.   {  light = [lightList objectAt:i];
  1287.      if (!strcmp(argv[1], [light shapeName]))
  1288.      {  [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  1289.         beamDistribution = (RtFloat)atof(argv[2]);
  1290.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1291.         return TCL_OK;
  1292.      }
  1293.   }
  1294.  
  1295.   for (i = 0; i < [otherLightList count]; i++)
  1296.   {  light = [otherLightList objectAt:i];
  1297.      if (!strcmp(argv[1], [light shapeName]))
  1298.      {  [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  1299.         beamDistribution = (RtFloat)atof(argv[2]);
  1300.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1301.         return TCL_OK;
  1302.      }
  1303.   }
  1304.  
  1305.   sprintf(errBuf, "no light named %s - unable to set beamDistribution...", argv[1]);
  1306.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1307.   return TCL_ERROR;
  1308. }
  1309.  
  1310.  
  1311. static int
  1312. cmd_removeLight(me, interp, argc, argv)
  1313. WW3DCamera *me;
  1314. Tcl_Interp *interp;
  1315. int argc;
  1316. char **argv;
  1317. {
  1318.   int            i;
  1319.  
  1320.  
  1321.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1322.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1323.   for (i = 1; i < argc; i++)
  1324.   {  if (![me removeLightNamed:argv[i]])
  1325.      {  sprintf(errBuf, "no light named %s - no further light removal done...", argv[i]);
  1326.         Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1327.         return TCL_ERROR;
  1328.      }
  1329.   }
  1330.  
  1331.   return TCL_OK;
  1332. }
  1333.  
  1334.  
  1335. static int
  1336. cmd_rotateAroundY(me, interp, argc, argv)
  1337. WW3DCamera *me;
  1338. Tcl_Interp *interp;
  1339. int argc;
  1340. char **argv;
  1341. {
  1342.   char       *my_args = "u", **argv2, *str;
  1343.   int         num_args = 2, argc2;
  1344.   RtPoint    originalView;
  1345.   RtPoint    originalEye, newEye;
  1346.   double     u, radius, radiusSq;
  1347.   RtFloat    originalRollAngle;
  1348.  
  1349.  
  1350.   //sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1351.   //[[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1352.  
  1353.   if (argc != num_args)
  1354.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1355.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1356.      return TCL_ERROR;
  1357.   }
  1358.  
  1359.   // u varies from 0 to 1, and describes a perfect circle around the original look at point.
  1360.   // we want to stay at the same Y point, and move around in a circle, such that the radius
  1361.   // of the circle we're describing stays constant.  
  1362.   // we just want to set a new eye point and then reset the viewpoint to be the same as it had been.
  1363.   u = (float)atof(argv[1]);
  1364.   
  1365.   // need to grab "startCam(eyePoint)", which is a list
  1366.   str = [[me tclInterp] getVar2:"startCam" :"eyePoint"];
  1367.   if (!str)
  1368.   {  sprintf(errBuf, "startCam(viewPoint) is no defined - unable to interpolate");
  1369.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1370.      return TCL_ERROR;
  1371.   }
  1372.   Tcl_SplitList(interp, str, &argc2, &argv2);
  1373.   if (argc2 != 3)
  1374.   {  sprintf(errBuf, "startCam(eyePoint) is supposed to have 3 elements, not %d", argc2);
  1375.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1376.      return TCL_ERROR;
  1377.   }
  1378.   N3D_XComp(originalEye) = (float)atof(argv2[0]);
  1379.   N3D_YComp(originalEye) = (float)atof(argv2[1]);
  1380.   N3D_ZComp(originalEye) = (float)atof(argv2[2]);
  1381.  
  1382.   // need to grab "startCam(viewPoint)", which is a list
  1383.   str = [[me tclInterp] getVar2:"startCam" :"viewPoint"];
  1384.   if (!str)
  1385.   {  sprintf(errBuf, "startCam(viewPoint) is no defined - unable to interpolate");
  1386.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1387.      return TCL_ERROR;
  1388.   }
  1389.   Tcl_SplitList(interp, str, &argc2, &argv2);
  1390.   if (argc2 != 3)
  1391.   {  sprintf(errBuf, "startCam(viewPoint) is supposed to have 3 elements, not %d", argc2);
  1392.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1393.      return TCL_ERROR;
  1394.   }
  1395.   N3D_XComp(originalView) = (float)atof(argv2[0]);
  1396.   N3D_YComp(originalView) = (float)atof(argv2[1]);
  1397.   N3D_ZComp(originalView) = (float)atof(argv2[2]);
  1398.  
  1399.   radiusSq =   ((N3D_XComp(originalEye) - N3D_XComp(originalView)) * (N3D_XComp(originalEye) - N3D_XComp(originalView)))
  1400.              + ((N3D_ZComp(originalEye) - N3D_ZComp(originalView)) * (N3D_ZComp(originalEye) - N3D_ZComp(originalView)));
  1401.   radius = sqrt(radiusSq);
  1402.   NXLogError("radius == %f\n", radius);
  1403.   N3D_XComp(newEye) = N3D_XComp(originalView) + ((N3D_XComp(originalEye) - N3D_XComp(originalView)) * cos(2 * PI * u));
  1404.   N3D_YComp(newEye) = N3D_YComp(originalEye);
  1405.   N3D_ZComp(newEye) = N3D_ZComp(originalView) + ((N3D_ZComp(originalEye) - N3D_ZComp(originalView)) * sin(2 * PI * u));
  1406.  
  1407.   // need to grab "startCam(rollAngle)"
  1408.   str = [[me tclInterp] getVar2:"startCam" :"rollAngle"];
  1409.   originalRollAngle = (RtFloat)atof(str);
  1410.  
  1411.   [me setEyeAt:newEye toward:originalView roll:originalRollAngle];
  1412.  
  1413.   return TCL_OK;
  1414. }
  1415.  
  1416. static int
  1417. cmd_noop(me, interp, argc, argv)
  1418. WW3DCamera *me;
  1419. Tcl_Interp *interp;
  1420. int argc;
  1421. char **argv;
  1422. {
  1423.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1424.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1425.   return TCL_OK;
  1426. }
  1427.  
  1428. #if 0
  1429. static int
  1430. cmd_(me, interp, argc, argv)
  1431. WW3DCamera *me;
  1432. Tcl_Interp *interp;
  1433. int argc;
  1434. char **argv;
  1435. {
  1436.   char  *my_args = "";
  1437.   int    num_args = 1;
  1438.  
  1439.  
  1440.   if (argc != num_args)
  1441.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1442.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1443.      return TCL_ERROR;
  1444.   }
  1445.  
  1446.   return TCL_OK;
  1447. }
  1448. #endif
  1449.  
  1450. - initInterp
  1451. {
  1452.   [tclInterp addCommand:"dumpRIBToFile" :cmd_dumpRIBToFile :self];
  1453.   [tclInterp addCommand:"display" :cmd_display :self];
  1454.   [tclInterp addCommand:"backgroundColor" :cmd_backgroundColor :self];
  1455.   [tclInterp addCommand:"fieldOfView" :cmd_fieldOfView :self];
  1456.   [tclInterp addCommand:"setEyeAt:toward:roll:" :cmd_setEyeAtTowardRoll :self];
  1457.   [tclInterp addCommand:"setEyeAtTowardRoll" :cmd_setEyeAtTowardRoll :self];
  1458.   [tclInterp addCommand:"moveEyeBy:::" :cmd_moveEyeBy :self];
  1459.   [tclInterp addCommand:"moveEyeBy" :cmd_moveEyeBy :self];
  1460.   [tclInterp addCommand:"setSurfaceTypeForAll" :cmd_setSurfaceTypeForAll :self];
  1461.   [tclInterp addCommand:"getEyePoint" :cmd_getEyePoint :self];
  1462.   [tclInterp addCommand:"getViewPoint" :cmd_getViewPoint :self];
  1463.   [tclInterp addCommand:"getRollAngle" :cmd_getRollAngle :self];
  1464.   [tclInterp addCommand:"getEyeAt:toward:roll:" :cmd_getEyeAtTowardRoll :self];
  1465.   [tclInterp addCommand:"getEyeAtTowardRoll" :cmd_getEyeAtTowardRoll :self];
  1466.   [tclInterp addCommand:"removeDefaultLights" :cmd_removeDefaultLights :self];
  1467.   [tclInterp addCommand:"restoreDefaultLights" :cmd_restoreDefaultLights :self];
  1468.   [tclInterp addCommand:"lightList" :cmd_lightList :self];
  1469.   [tclInterp addCommand:"otherLightList" :cmd_otherLightList :self];
  1470.   [tclInterp addCommand:"localLightList" :cmd_otherLightList :self];
  1471.   [tclInterp addCommand:"addAmbientLight" :cmd_addAmbientLight :self];
  1472.   [tclInterp addCommand:"addPointLight" :cmd_addPointLight :self];
  1473.   [tclInterp addCommand:"addDistantLight" :cmd_addDistantLight :self];
  1474.   [tclInterp addCommand:"addSpotLight" :cmd_addSpotLight :self];
  1475.   [tclInterp addCommand:"setLightIntensity" :cmd_setLightIntensity :self];
  1476.   [tclInterp addCommand:"setLightType" :cmd_setLightType :self];
  1477.   [tclInterp addCommand:"setLightFrom" :cmd_setLightFrom :self];
  1478.   [tclInterp addCommand:"setLightTo" :cmd_setLightTo :self];
  1479.   [tclInterp addCommand:"setLightColor" :cmd_setLightColor :self];
  1480.   [tclInterp addCommand:"setLightConeAngleConeDeltaBeamDistribution" :cmd_setLightConeAngleConeDeltaBeamDistribution :self];
  1481.   [tclInterp addCommand:"setLightConeAngle" :cmd_setLightConeAngle :self];
  1482.   [tclInterp addCommand:"setLightConeDelta" :cmd_setLightConeDelta :self];
  1483.   [tclInterp addCommand:"setLightBeamDistribution" :cmd_setLightBeamDistribution :self];
  1484.   [tclInterp addCommand:"removeLight" :cmd_removeLight :self];
  1485.  
  1486.   [tclInterp addCommand:"rotateAroundY" :cmd_rotateAroundY :self];
  1487.  
  1488.   [tclInterp addCommand:"askModel" :cmd_noop :self];
  1489.   [tclInterp addCommand:"noop" :cmd_noop :self];
  1490.  
  1491.   return self;
  1492. }
  1493.  
  1494. - setupDefaultLights
  1495. {
  1496.    RtPoint lFromP = {0.5,0.5,-0.75};
  1497.    RtPoint lToP = {0, 0, 0};
  1498.  
  1499.    // ambient light
  1500.    ambientLight=[[WW3DLight alloc] init];
  1501.    [ambientLight setShapeName:"ambientLight"];
  1502.    [ambientLight makeAmbientWithIntensity:0.3];
  1503.    [self addLight:ambientLight];
  1504.  
  1505.    // distant light
  1506.    rightLight=[[WW3DLight alloc] init];
  1507.    [rightLight setShapeName:"rightDistantLight"];
  1508.    [rightLight makeDistantFrom:lFromP to:lToP intensity:0.7];
  1509.    [self addLight:rightLight];
  1510.  
  1511.   // point light
  1512.   //N3D_XComp( lFromP ) = -0.5;
  1513.   //N3D_YComp( lFromP ) = -0.5;
  1514.   //leftLight=[[WW3DLight alloc] init];
  1515.   //[leftLight setShapeName:"leftPointLight"];
  1516.   //[leftLight makePointFrom:lFromP intensity:0.7];
  1517.   //[self addLight:leftLight];
  1518.  
  1519.   defaultLightsInUse = YES;
  1520.  
  1521.   return self;
  1522. }
  1523.  
  1524. - restoreDefaultLights
  1525. {
  1526.   if (!defaultLightsInUse)
  1527.   {  [self addLight:ambientLight];
  1528.      [self addLight:rightLight];
  1529.      //[self addLight:leftLight];
  1530.      defaultLightsInUse = YES;
  1531.   }
  1532.   return self;
  1533. }
  1534.  
  1535. - removeDefaultLights
  1536. {
  1537.   if (defaultLightsInUse)
  1538.   {  [self removeLight:ambientLight];
  1539.      [self removeLight:rightLight];
  1540.      [self removeLight:leftLight];
  1541.      defaultLightsInUse = NO;
  1542.   }
  1543.   return self;
  1544. }
  1545.  
  1546.  
  1547. - removeLightNamed:(const char *)lightName
  1548. {
  1549.    int  i;
  1550.    id   light;
  1551.  
  1552.  
  1553.    for (i = 0; i < [lightList count]; i++)
  1554.    {  light = [lightList objectAt:i];
  1555.       if (!strcmp(lightName, [light shapeName]))
  1556.       {  [self removeLight:light];
  1557.          return self;
  1558.       }
  1559.    }
  1560.    return nil;
  1561. }
  1562.  
  1563.  
  1564. - setFieldOfViewByAngle:(float)viewAngle
  1565. {
  1566.   char   buf[128];
  1567.  
  1568.  
  1569.   [super setFieldOfViewByAngle:viewAngle];
  1570.   sprintf(buf, "%f", viewAngle);
  1571.   [tclInterp setVar2:"cam" :"fieldOfView" toValue:buf];
  1572.   //[delegate cameraParametersWereUpdated:self];
  1573.  
  1574.   return self;
  1575. }
  1576.  
  1577.  
  1578. char *ReadOnlyWriteProc(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1579. {
  1580.   return "this is a read-only variable";
  1581. }
  1582.  
  1583.  
  1584. char *WriteProcForInterpolationProc(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1585. {
  1586.   // when a new interpolation proc is defined, there are several things we want to do.
  1587.   // first of all, we want to make sure that it's valid:
  1588.   // - a valid interpolation proc only has one argument: u
  1589.  
  1590.   // the other thing we might want to do is update the inspector panel (if we have one) about the contents of this guy...
  1591.  
  1592.   return NULL;
  1593. }
  1594.  
  1595.  
  1596. // someone is writing a new value for the cam(fieldOfView) parameter, so we need
  1597. // to update the WW3DCamera to reflect that new value...
  1598.  
  1599. // really should constrain fov to be from <0 && <180
  1600. char *WriteProcForFieldOfViewByAngle(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1601. {
  1602.   char   *varString;
  1603.   float  fieldOfView = 45.;
  1604.  
  1605.  
  1606.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  1607.   sscanf(varString, "%f", &fieldOfView);
  1608.   [[(WWTCLVarTrace *)clientData datum] setFieldOfViewByAngle:fieldOfView];
  1609.  
  1610.   return NULL;
  1611. }
  1612.  
  1613.  
  1614. // someone is reading a value for the cam(fieldOfView) parameter, so we need
  1615. // to " read-through" the WW3DCamera to reflect the current value...
  1616. char *ReadProcForFieldOfViewByAngle(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1617. {
  1618.   char   buf[128];
  1619.   float  fieldOfView;
  1620.  
  1621.  
  1622.   fieldOfView = [[(WWTCLVarTrace *)clientData datum] fieldOfView];
  1623.   sprintf(buf, "%f", fieldOfView);
  1624.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  1625.  
  1626.   return NULL;
  1627. }
  1628.  
  1629. - setEyeAt:(RtPoint)fromPoint toward:(RtPoint)toPoint roll:(float)aRollAngle;
  1630. {
  1631.   char   buf[384];
  1632.  
  1633.  
  1634.   [super setEyeAt:fromPoint toward:toPoint roll:aRollAngle];
  1635.  
  1636.   sprintf(buf, "%f %f %f", N3D_XComp(fromPoint), N3D_YComp(fromPoint), N3D_ZComp(fromPoint));
  1637.   [tclInterp setVar2:"cam" :"eyePoint" toValue:buf];
  1638.   sprintf(buf, "%f %f %f", N3D_XComp(toPoint), N3D_YComp(toPoint), N3D_ZComp(toPoint));
  1639.   [tclInterp setVar2:"cam" :"viewPoint" toValue:buf];
  1640.   sprintf(buf, "%f", aRollAngle);
  1641.   [tclInterp setVar2:"cam" :"rollAngle" toValue:buf];
  1642.  
  1643.   //[delegate cameraParametersWereUpdated:self];
  1644.   return self;
  1645. }
  1646.  
  1647. // someone is writing a new value for the cam(eyePoint) parameter, so we need
  1648. // to update the WW3DCamera to reflect that new value...
  1649. char *WriteProcForEyePoint(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1650. {
  1651.   char     *varString, **argv;
  1652.   int      argc;
  1653.   RtPoint  anEyePoint, aViewPoint;
  1654.   RtFloat  aRollAngle;
  1655.  
  1656.  
  1657.   // get current values
  1658.   [[(WWTCLVarTrace *)clientData datum] getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  1659.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  1660.   Tcl_SplitList(interp, varString, &argc, &argv); // fromPoint
  1661.   if (argc != 3)
  1662.   {  NXLogError("cam(eyePoint) should be a tcl list with 3 components, not <%s>\n", varString);
  1663.      if (argv) { free(argv); }
  1664.      return NULL;
  1665.   }
  1666.   N3D_XComp(anEyePoint) = (float)atof(argv[0]);
  1667.   N3D_YComp(anEyePoint) = (float)atof(argv[1]);
  1668.   N3D_ZComp(anEyePoint) = (float)atof(argv[2]);
  1669.   free(argv);
  1670.  
  1671.   [[(WWTCLVarTrace *)clientData datum] setEyeAt:anEyePoint toward:aViewPoint roll:aRollAngle];
  1672.  
  1673.   return NULL;
  1674. }
  1675.  
  1676.  
  1677. // someone is reading a value for the cam() parameter, so we need
  1678. // to " read-through" the WW3DCamera to reflect the current value...
  1679. char *ReadProcForEyePoint(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1680. {
  1681.   char     buf[384];
  1682.   RtPoint  anEyePoint, aViewPoint;
  1683.   RtFloat  aRollAngle;
  1684.  
  1685.  
  1686.   // get current values
  1687.   [[(WWTCLVarTrace *)clientData datum] getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  1688.  
  1689.   sprintf(buf, "%f %f %f", N3D_XComp(anEyePoint), N3D_YComp(anEyePoint), N3D_ZComp(anEyePoint));
  1690.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  1691.  
  1692.   return NULL;
  1693. }
  1694.  
  1695. // someone is writing a new value for the cam(viewPoint) parameter, so we need
  1696. // to update the WW3DCamera to reflect that new value...
  1697. char *WriteProcForViewPoint(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1698. {
  1699.   char     *varString, **argv;
  1700.   int      argc;
  1701.   RtPoint  anEyePoint, aViewPoint;
  1702.   RtFloat  aRollAngle;
  1703.  
  1704.  
  1705.   // get current values
  1706.   [[(WWTCLVarTrace *)clientData datum] getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  1707.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  1708.   Tcl_SplitList(interp, varString, &argc, &argv); // viewPoint
  1709.   if (argc != 3)
  1710.   {  NXLogError("cam(viewPoint) should be a tcl list with 3 components, not <%s>\n", varString);
  1711.      if (argv) { free(argv); }
  1712.      return NULL;
  1713.   }
  1714.   N3D_XComp(aViewPoint) = (float)atof(argv[0]);
  1715.   N3D_YComp(aViewPoint) = (float)atof(argv[1]);
  1716.   N3D_ZComp(aViewPoint) = (float)atof(argv[2]);
  1717.   free(argv);
  1718.  
  1719.   [[(WWTCLVarTrace *)clientData datum] setEyeAt:anEyePoint toward:aViewPoint roll:aRollAngle];
  1720.  
  1721.   return NULL;
  1722. }
  1723.  
  1724.  
  1725. // someone is reading a value for the cam(viewPoint) parameter, so we need
  1726. // to " read-through" the WW3DCamera to reflect the current value...
  1727. char *ReadProcForViewPoint(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1728. {
  1729.   char     buf[384];
  1730.   RtPoint  anEyePoint, aViewPoint;
  1731.   RtFloat  aRollAngle;
  1732.  
  1733.  
  1734.   // get current values
  1735.   [[(WWTCLVarTrace *)clientData datum] getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  1736.  
  1737.   sprintf(buf, "%f %f %f", N3D_XComp(aViewPoint), N3D_YComp(aViewPoint), N3D_ZComp(aViewPoint));
  1738.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  1739.  
  1740.   return NULL;
  1741. }
  1742.  
  1743. // someone is writing a new value for the cam(rollAngle) parameter, so we need
  1744. // to update the WW3DCamera to reflect that new value...
  1745. char *WriteProcForRollAngle(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1746. {
  1747.   char     *varString;
  1748.   RtPoint  anEyePoint, aViewPoint;
  1749.   RtFloat  aRollAngle;
  1750.  
  1751.  
  1752.   // get current values
  1753.   [[(WWTCLVarTrace *)clientData datum] getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  1754.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  1755.   aRollAngle = (float)atof(varString);
  1756.  
  1757.   [[(WWTCLVarTrace *)clientData datum] setEyeAt:anEyePoint toward:aViewPoint roll:aRollAngle];
  1758.  
  1759.   return NULL;
  1760. }
  1761.  
  1762.  
  1763. // someone is reading a value for the cam(rollAngle) parameter, so we need
  1764. // to " read-through" the WW3DCamera to reflect the current value...
  1765. char *ReadProcForRollAngle(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1766. {
  1767.   char     buf[384];
  1768.   RtPoint  anEyePoint, aViewPoint;
  1769.   RtFloat  aRollAngle;
  1770.  
  1771.  
  1772.   // get current values
  1773.   [[(WWTCLVarTrace *)clientData datum] getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  1774.  
  1775.   sprintf(buf, "%f", aRollAngle);
  1776.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  1777.  
  1778.   return NULL;
  1779. }
  1780.  
  1781.  
  1782. - (RtFloat)fStop { return fStop; }
  1783.  
  1784. - setFStop:(float)newFStop
  1785. {
  1786.   char   buf[128];
  1787.  
  1788.  
  1789.   fStop = newFStop;
  1790.   sprintf(buf, "%f", fStop);
  1791.   [tclInterp setVar2:"cam" :"fStop" toValue:buf];
  1792.   //[delegate cameraParametersWereUpdated:self];
  1793.  
  1794.   return self;
  1795. }
  1796.  
  1797.  
  1798. // someone is writing a new value for the cam(fStop) parameter, so we need
  1799. // to update the WW3DCamera to reflect that new value...
  1800. char *WriteProcForFStop(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1801. {
  1802.   char   *varString;
  1803.   float  fStop = 1.0;
  1804.  
  1805.  
  1806.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  1807.   sscanf(varString, "%f", &fStop);
  1808.   [[(WWTCLVarTrace *)clientData datum] setFStop:fStop];
  1809.  
  1810.   return NULL;
  1811. }
  1812.  
  1813.  
  1814. // someone is reading a value for the cam(fStop) parameter, so we need
  1815. // to " read-through" the WW3DCamera to reflect the current value...
  1816. char *ReadProcForFStop(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1817. {
  1818.   char   buf[128];
  1819.   float  fStop;
  1820.  
  1821.  
  1822.   fStop = [[(WWTCLVarTrace *)clientData datum] fStop];
  1823.   sprintf(buf, "%f", fStop);
  1824.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  1825.  
  1826.   return NULL;
  1827. }
  1828.  
  1829. - (RtFloat)focalLength { return focalLength; }
  1830.  
  1831. - setFocalLength:(float)newFocalLength
  1832. {
  1833.   char   buf[128];
  1834.  
  1835.  
  1836.   focalLength = newFocalLength;
  1837.   sprintf(buf, "%f", focalLength);
  1838.   [tclInterp setVar2:"cam" :"focalLength" toValue:buf];
  1839.   //[delegate cameraParametersWereUpdated:self];
  1840.  
  1841.   return self;
  1842. }
  1843.  
  1844.  
  1845. // someone is writing a new value for the cam(fStop) parameter, so we need
  1846. // to update the WW3DCamera to reflect that new value...
  1847. char *WriteProcForFocalLength(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1848. {
  1849.   char   *varString;
  1850.   float  focalLength = 1.0;
  1851.  
  1852.  
  1853.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  1854.   sscanf(varString, "%f", &focalLength);
  1855.   [[(WWTCLVarTrace *)clientData datum] setFocalLength:focalLength];
  1856.  
  1857.   return NULL;
  1858. }
  1859.  
  1860.  
  1861. // someone is reading a value for the cam(fStop) parameter, so we need
  1862. // to " read-through" the WW3DCamera to reflect the current value...
  1863. char *ReadProcForFocalLength(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1864. {
  1865.   char   buf[128];
  1866.   float  focalLength;
  1867.  
  1868.  
  1869.   focalLength = [[(WWTCLVarTrace *)clientData datum] focalLength];
  1870.   sprintf(buf, "%f", focalLength);
  1871.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  1872.  
  1873.   return NULL;
  1874. }
  1875.  
  1876. - (RtFloat)focalDistance { return focalDistance; }
  1877.  
  1878. - setFocalDistance:(float)newFocalDistance
  1879. {
  1880.   char   buf[128];
  1881.  
  1882.  
  1883.   focalDistance = newFocalDistance;
  1884.   sprintf(buf, "%f", focalDistance);
  1885.   [tclInterp setVar2:"cam" :"focalDistance" toValue:buf];
  1886.   //[delegate cameraParametersWereUpdated:self];
  1887.  
  1888.   return self;
  1889. }
  1890.  
  1891.  
  1892. // someone is writing a new value for the cam(focalDistance) parameter, so we need
  1893. // to update the WW3DCamera to reflect that new value...
  1894. char *WriteProcForFocalDistance(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1895. {
  1896.   char   *varString;
  1897.   float  focalDistance = 1.0;
  1898.  
  1899.  
  1900.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  1901.   sscanf(varString, "%f", &focalDistance);
  1902.   [[(WWTCLVarTrace *)clientData datum] setFocalDistance:focalDistance];
  1903.  
  1904.   return NULL;
  1905. }
  1906.  
  1907.  
  1908. // someone is reading a value for the cam(focalDistance) parameter, so we need
  1909. // to " read-through" the WW3DCamera to reflect the current value...
  1910. char *ReadProcForFocalDistance(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1911. {
  1912.   char   buf[128];
  1913.   float  focalDistance;
  1914.  
  1915.  
  1916.   focalDistance = [[(WWTCLVarTrace *)clientData datum] focalDistance];
  1917.   sprintf(buf, "%f", focalDistance);
  1918.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  1919.  
  1920.   return NULL;
  1921. }
  1922.  
  1923. - setFrameNumber:(int)aFrameNumber
  1924. {
  1925.   char   buf[128];
  1926.  
  1927.  
  1928.   if ((aFrameNumber <= [self endFrame]) && ([self frameNumber] != aFrameNumber))  //it's valid and it's new
  1929.   {  // if it's actually a new frame, we need to flip the "evaluateInterpProc"
  1930.      // flag, so that the next time we render, we run the camera interpolation routine...
  1931.      evaluateInterpProc = YES;
  1932.   }
  1933.  
  1934.   // we assume that the [super setFrameNumber:]  clamps to endFrameNumber
  1935.   [super setFrameNumber:aFrameNumber];
  1936.  
  1937.   // by setting the frame number, we need to make sure that all the
  1938.   // appropriate other parts of the camera have been updated.  What
  1939.   // automatically follows along?  Well, the shutterOpenTime needs to get
  1940.   // updated, at least...
  1941.   [self setShutterOpenTime:(shotStartTime + (frameNumber * frameTimeIncrement))];
  1942.  
  1943.   sprintf(buf, "%d", frameNumber);
  1944.   [tclInterp setVar2:"cam" :"frameNumber" toValue:buf];
  1945.   //[delegate cameraParametersWereUpdated:self];
  1946.  
  1947.   return self;
  1948. }
  1949.  
  1950.  
  1951. - resetFrameNumber
  1952. {
  1953.   [self setFrameNumber:0];
  1954.   return self;
  1955. }
  1956.  
  1957. // someone is writing a new value for the cam(frameNumber) parameter, so we need
  1958. // to update the WW3DCamera to reflect that new value...
  1959. char *WriteProcForFrameNumber(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1960. {
  1961.   char   *varString;
  1962.   int    frameNumber = 1;
  1963.  
  1964.  
  1965.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  1966.  
  1967.   // frameNumber has to be an integer
  1968.  
  1969.  
  1970.   sscanf(varString, "%d", &frameNumber);
  1971.   [[(WWTCLVarTrace *)clientData datum] setFrameNumber:frameNumber];
  1972.  
  1973.   return NULL;
  1974. }
  1975.  
  1976.  
  1977. // someone is reading a value for the cam(frameNumber) parameter, so we need
  1978. // to " read-through" the WW3DCamera to reflect the current value...
  1979. char *ReadProcForFrameNumber(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1980. {
  1981.   char   buf[128];
  1982.   int    frameNumber;
  1983.  
  1984.  
  1985.   frameNumber = [[(WWTCLVarTrace *)clientData datum] frameNumber];
  1986.   sprintf(buf, "%d", frameNumber);
  1987.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  1988.  
  1989.   return NULL;
  1990. }
  1991.  
  1992. // whenever the frame number or the frameTimeIncrement gets changed,
  1993. // the open and close time need to be recalculated
  1994.  
  1995. - (RtFloat)shutterOpenTime { return shutterOpenTime; }
  1996.  
  1997. - setShutterOpenTime:(RtFloat)newShutterOpenTime
  1998. {
  1999.   char   buf[128];
  2000.  
  2001.  
  2002.   shutterOpenTime = newShutterOpenTime;
  2003.   sprintf(buf, "%f", shutterOpenTime);
  2004.   [tclInterp setVar2:"cam" :"shutterOpenTime" toValue:buf];
  2005.   //[delegate cameraParametersWereUpdated:self];
  2006.  
  2007.   return self;
  2008. }
  2009.  
  2010.  
  2011. // someone is writing a new value for the cam(shutterOpenTime) parameter, so we need
  2012. // to update the WW3DCamera to reflect that new value...
  2013. char *WriteProcForShutterOpenTime(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2014. {
  2015.   char   *varString;
  2016.   RtFloat  shutterOpenTime = 0.0;
  2017.  
  2018.  
  2019.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2020.   sscanf(varString, "%f", &shutterOpenTime);
  2021.   [[(WWTCLVarTrace *)clientData datum] setShutterOpenTime:shutterOpenTime];
  2022.  
  2023.   return NULL;
  2024. }
  2025.  
  2026.  
  2027. // someone is reading a value for the cam(shutterOpenTime) parameter, so we need
  2028. // to " read-through" the WW3DCamera to reflect the current value...
  2029. char *ReadProcForShutterOpenTime(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2030. {
  2031.   char   buf[128];
  2032.   RtFloat  shutterOpenTime;
  2033.  
  2034.  
  2035.   shutterOpenTime = [[(WWTCLVarTrace *)clientData datum] shutterOpenTime];
  2036.   sprintf(buf, "%f", shutterOpenTime);
  2037.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2038.  
  2039.   return NULL;
  2040. }
  2041.  
  2042. - (RtFloat)shutterCloseTime { return (shutterOpenTime + (exposureLength * exposureLengthFactor)); }
  2043.  
  2044. // someone is writing a new value for the cam(shutterCloseTime) parameter, so we need
  2045. // to update the WW3DCamera to reflect that new value...
  2046. char *WriteProcForShutterCloseTime(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2047. {
  2048.   return "cam(shutterCloseTime) is read-only";
  2049. }
  2050.  
  2051.  
  2052. // someone is reading a value for the cam(shutterCloseTime) parameter, so we need
  2053. // to " read-through" the WW3DCamera to reflect the current value...
  2054. char *ReadProcForShutterCloseTime(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2055. {
  2056.   char   buf[128];
  2057.   RtFloat  shutterCloseTime;
  2058.  
  2059.  
  2060.   shutterCloseTime = [[(WWTCLVarTrace *)clientData datum] shutterCloseTime];
  2061.   sprintf(buf, "%f", shutterCloseTime);
  2062.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2063.  
  2064.   return NULL;
  2065. }
  2066.  
  2067. - (float)frameTimeIncrement { return frameTimeIncrement; }
  2068.  
  2069. - (float)exposureLength { return exposureLength; }
  2070.  
  2071. - setExposureLength:(float)newExposureLength
  2072. {
  2073.   char   buf[128];
  2074.  
  2075.   // need to make sure that the new exposure length is consistent with the rest of the camera
  2076.   // what does this mean?
  2077.   // the length of the exposure cannot be longer than the interval between frames, i.e. 
  2078.   // exposureLength <= (frameTimeIncrement == 1./framesPerSecond)
  2079.   // 
  2080.   //NXLogError("newExposureLength == %f\n", newExposureLength);
  2081.  
  2082.   if (newExposureLength < 0.0)
  2083.   {  NXLogError("exposureLength must be a positive number, not %f\n", newExposureLength);
  2084.      return nil;
  2085.   }
  2086.  
  2087.   // actually, we only want to do this if we're shooting.  Anyway, at
  2088.   // the start of shooting a shot (i.e. an ordered sequence), we should
  2089.   // sanity check then - this might be perfectly reasonable for a still
  2090.   // frame...
  2091.   if (shooting)
  2092.   {  if (newExposureLength > [self frameTimeIncrement])
  2093.      {  exposureLength = [self frameTimeIncrement];
  2094.      }
  2095.      else
  2096.      {  exposureLength = newExposureLength;
  2097.      }
  2098.   }
  2099.   else  // don't do a clip; it could be whatever positive value they want...
  2100.   {  exposureLength = newExposureLength;
  2101.   }
  2102.   sprintf(buf, "%f", exposureLength);
  2103.   [tclInterp setVar2:"cam" :"exposureLength" toValue:buf];
  2104.   //[delegate cameraParametersWereUpdated:self];
  2105.   justResetExposureLength = YES;
  2106.  
  2107.  
  2108.   return self;
  2109. }
  2110.  
  2111.  
  2112. // someone is writing a new value for the cam(exposureLength) parameter, so we need
  2113. // to update the WW3DCamera to reflect that new value...
  2114. char *WriteProcForExposureLength(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2115. {
  2116.   char   *varString;
  2117.   RtFloat  exposureLength = 0.0;
  2118.  
  2119.  
  2120.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2121.   sscanf(varString, "%f", &exposureLength);
  2122.   [[(WWTCLVarTrace *)clientData datum] setExposureLength:exposureLength];
  2123.  
  2124.   return NULL;
  2125. }
  2126.  
  2127.  
  2128. // someone is reading a value for the cam(exposureLength) parameter, so we need
  2129. // to " read-through" the WW3DCamera to reflect the current value...
  2130. char *ReadProcForExposureLength(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2131. {
  2132.   char   buf[128];
  2133.   RtFloat  exposureLength;
  2134.  
  2135.  
  2136.   exposureLength = [[(WWTCLVarTrace *)clientData datum] exposureLength];
  2137.   sprintf(buf, "%f", exposureLength);
  2138.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2139.  
  2140.   return NULL;
  2141. }
  2142.  
  2143. - (float)framesPerSecond { return framesPerSecond; }
  2144.  
  2145. - setFramesPerSecond:(float)newFramesPerSecond
  2146. {
  2147.   char     buf[128];
  2148.   RtFloat  maxExposureLength;
  2149.   int      newEndFrame;
  2150.  
  2151.  
  2152.   // okay, the frames/second is being changed.  
  2153.   // what do we need to update?
  2154.   // we want the duration of the shot (in seconds) to stay the same, 
  2155.   // so we need to:
  2156.   // - make sure that the exposureLength is still valid; if not, clamp it
  2157.   // - reset the startFrame to 0 and the endFrame to whatever is appropriate 
  2158.  
  2159.   framesPerSecond = newFramesPerSecond;
  2160.   sprintf(buf, "%f", newFramesPerSecond);
  2161.   [tclInterp setVar2:"cam" :"FramesPerSecond" toValue:buf];
  2162.  
  2163.   frameTimeIncrement = (1.0/framesPerSecond);
  2164.   maxExposureLength = frameTimeIncrement;
  2165.  
  2166.   // if, by changing the frame rate, we've invalidated the current
  2167.   // setting for how long the shutter stays open for each frame, we need to
  2168.   // reset it to a valid value.  If it's still valid, leave it be (i.e. if
  2169.   // it was a strobe camera, it will stay that way).
  2170.   // uh, no.  There are two normal cases: keep the exposureLength at 0.0, for a strobe,
  2171.   // or keep the exposureLength == frameTimeIncrement.  So... if they want a special
  2172.   // setting, they'll need to reset it after setting a new fps.
  2173.   // uh, no I changed my mind again.  If they want a *strobe*, they have to reset it explicitly
  2174.   // this is what I want in most cases (i.e. I want motion blur)
  2175.   [self setExposureLength:maxExposureLength];
  2176.  
  2177.   newEndFrame = (framesPerSecond * [self shotLength]); // actually should do the right thing at the half frame mark...
  2178.   [super setStartFrame:0 endFrame:newEndFrame incrementFramesBy:[self frameIncrement]];
  2179.  
  2180.   //[delegate cameraParametersWereUpdated:self];
  2181.  
  2182.   return self;
  2183. }
  2184.  
  2185.  
  2186. // someone is writing a new value for the cam(framesPerSecond) parameter, so we need
  2187. // to update the WW3DCamera to reflect that new value...
  2188. char *WriteProcForFramesPerSecond(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2189. {
  2190.   char   *varString;
  2191.   float  framesPerSecond = 17.0;
  2192.  
  2193.  
  2194.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2195.  
  2196.   // framesPerSecond has to be a float
  2197.   sscanf(varString, "%f", &framesPerSecond);
  2198.   [[(WWTCLVarTrace *)clientData datum] setFramesPerSecond:framesPerSecond];
  2199.  
  2200.   return NULL;
  2201. }
  2202.  
  2203.  
  2204. // someone is reading a value for the cam(framesPerSecond) parameter, so we need
  2205. // to " read-through" the WW3DCamera to reflect the current value...
  2206. char *ReadProcForFramesPerSecond(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2207. {
  2208.   char   buf[128];
  2209.   float  framesPerSecond;
  2210.  
  2211.  
  2212.   framesPerSecond = [[(WWTCLVarTrace *)clientData datum] framesPerSecond];
  2213.   sprintf(buf, "%f", framesPerSecond);
  2214.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2215.  
  2216.   return NULL;
  2217. }
  2218.  
  2219. - (float)shotLength { return shotLength; }
  2220.  
  2221. - setShotLength:(float)newShotLength
  2222. {
  2223.   char     buf[128];
  2224.   int      newEndFrame;
  2225.  
  2226.  
  2227.   // okay, the frames/second is being changed.  
  2228.   // what do we need to update?
  2229.   // - reset the startFrame to 0 and the endFrame to whatever is appropriate 
  2230.  
  2231.   shotLength = newShotLength;
  2232.   sprintf(buf, "%f", newShotLength);
  2233.   [tclInterp setVar2:"cam" :"shotLength" toValue:buf];
  2234.  
  2235.   newEndFrame = (shotLength * [self framesPerSecond]) - 1; // actually should the right thing at the half frame mark...
  2236.   [super setStartFrame:0 endFrame:newEndFrame incrementFramesBy:[self frameIncrement]];
  2237.  
  2238.   //[delegate cameraParametersWereUpdated:self];
  2239.  
  2240.   return self;
  2241. }
  2242.  
  2243.  
  2244. // someone is writing a new value for the cam(shotLength) parameter, so we need
  2245. // to update the WW3DCamera to reflect that new value...
  2246. char *WriteProcForShotLength(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2247. {
  2248.   char   *varString;
  2249.   float  shotLength = 17.0;
  2250.  
  2251.  
  2252.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2253.  
  2254.   // ShotLength has to be a float
  2255.   sscanf(varString, "%f", &shotLength);
  2256.   [[(WWTCLVarTrace *)clientData datum] setShotLength:shotLength];
  2257.  
  2258.   return NULL;
  2259. }
  2260.  
  2261.  
  2262. // someone is reading a value for the cam(ShotLength) parameter, so we need
  2263. // to " read-through" the WW3DCamera to reflect the current value...
  2264. char *ReadProcForShotLength(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2265. {
  2266.   char   buf[128];
  2267.   float  shotLength;
  2268.  
  2269.  
  2270.   shotLength = [[(WWTCLVarTrace *)clientData datum] shotLength];
  2271.   sprintf(buf, "%f", shotLength);
  2272.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2273.  
  2274.   return NULL;
  2275. }
  2276.  
  2277. - (float)shotStartTime { return shotStartTime; }
  2278.  
  2279. - setShotStartTime:(float)newShotStartTime
  2280. {
  2281.   char     buf[128];
  2282.  
  2283.  
  2284.   shotStartTime = newShotStartTime;
  2285.   sprintf(buf, "%f", newShotStartTime);
  2286.   [tclInterp setVar2:"cam" :"shotStartTime" toValue:buf];
  2287.  
  2288.   //[delegate cameraParametersWereUpdated:self];
  2289.  
  2290.   return self;
  2291. }
  2292.  
  2293.  
  2294. // someone is writing a new value for the cam(shotStartTime) parameter, so we need
  2295. // to update the WW3DCamera to reflect that new value...
  2296. char *WriteProcForShotStartTime(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2297. {
  2298.   char   *varString;
  2299.   float  shotStartTime = 0.0;
  2300.  
  2301.  
  2302.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2303.  
  2304.   // ShotStartTime has to be a float
  2305.   sscanf(varString, "%f", &shotStartTime);
  2306.   [[(WWTCLVarTrace *)clientData datum] setShotStartTime:shotStartTime];
  2307.  
  2308.   return NULL;
  2309. }
  2310.  
  2311.  
  2312. // someone is reading a value for the cam(shotStartTime) parameter, so we need
  2313. // to " read-through" the WW3DCamera to reflect the current value...
  2314. char *ReadProcForShotStartTime(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2315. {
  2316.   char   buf[128];
  2317.   float  shotStartTime;
  2318.  
  2319.  
  2320.   shotStartTime = [[(WWTCLVarTrace *)clientData datum] shotStartTime];
  2321.   sprintf(buf, "%f", shotStartTime);
  2322.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2323.  
  2324.   return NULL;
  2325. }
  2326.  
  2327. - (float)exposureLengthFactor { return exposureLengthFactor; }
  2328.  
  2329. - setExposureLengthFactor:(float)newExposureLengthFactor
  2330. {
  2331.   char     buf[128];
  2332.  
  2333.  
  2334.   exposureLengthFactor = newExposureLengthFactor;
  2335.   // bound it inclusively between 0 and 1
  2336.   if (exposureLengthFactor < 0.0)
  2337.   {  exposureLengthFactor = 0.0;
  2338.   }
  2339.   if (exposureLengthFactor > 1.0)
  2340.   {  exposureLengthFactor = 1.0;
  2341.   }
  2342.   sprintf(buf, "%f", newExposureLengthFactor);
  2343.   [tclInterp setVar2:"cam" :"exposureLengthFactor" toValue:buf];
  2344.  
  2345.   //[delegate cameraParametersWereUpdated:self];
  2346.  
  2347.   return self;
  2348. }
  2349.  
  2350.  
  2351. // someone is writing a new value for the cam(exposureLengthFactor) parameter, so we need
  2352. // to update the WW3DCamera to reflect that new value...
  2353. char *WriteProcForExposureLengthFactor(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2354. {
  2355.   char   *varString;
  2356.   float  exposureLengthFactor = 0.0;
  2357.  
  2358.  
  2359.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2360.  
  2361.   // exposureLengthFactor has to be a float
  2362.   sscanf(varString, "%f", &exposureLengthFactor);
  2363.   [[(WWTCLVarTrace *)clientData datum] setExposureLengthFactor:exposureLengthFactor];
  2364.  
  2365.   return NULL;
  2366. }
  2367.  
  2368.  
  2369. // someone is reading a value for the cam(exposureLengthFactor) parameter, so we need
  2370. // to " read-through" the WW3DCamera to reflect the current value...
  2371. char *ReadProcForExposureLengthFactor(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2372. {
  2373.   char   buf[128];
  2374.   float  exposureLengthFactor;
  2375.  
  2376.  
  2377.   exposureLengthFactor = [[(WWTCLVarTrace *)clientData datum] exposureLengthFactor];
  2378.   sprintf(buf, "%f", exposureLengthFactor);
  2379.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2380.  
  2381.   return NULL;
  2382. }
  2383.  
  2384. - (BOOL)shooting { return shooting; }
  2385.  
  2386. - setShooting:(BOOL)newShooting
  2387. {
  2388.   if (shooting && !newShooting)
  2389.   {  justFinishedShooting = YES;
  2390.   }
  2391.   shooting = newShooting;
  2392.  
  2393.   return self;
  2394. }
  2395.  
  2396. - takeShooting:sender
  2397. {
  2398.   [self setShooting:(BOOL)[sender intValue]];
  2399.   return self;
  2400. }
  2401.  
  2402. // in this routine, the tcl interp is assumed to have the correct values, and so the camera has to conform to it...
  2403. // cam(fieldOfView) : fieldOfView : float -> float
  2404. // cam(eyePoint) : eyePoint : RtPoint -> {x y z}
  2405. // cam(viewPoint) : viewPoint : RtPoint -> {x y z}
  2406. // cam(rollAngle) : rollAngle : float -> float
  2407. // cam(fStop) : fStop : float -> float
  2408. // cam(focalLength) : focalLength : float -> float
  2409. // cam(focalDistance) : focalDistance : float -> float
  2410. // cam(frameNumber) : frameNumber : int -> int
  2411.  
  2412. // NOT DONE YET!
  2413. // cam(pixelAspectRatio) : pixelAspectRatio : float -> float
  2414. // cam(projectionType) : projectionType : N3DProjectionType -> string
  2415. // cam(backgroundColor) : backgroundColor : NXColor -> {r g b}
  2416. // cam(doesDrawBackgroundColor) : doesDrawBackgroundColor : BOOL -> int
  2417. // cam(nearPlane) : nearPlane : float -> float
  2418. // cam(farPlane) : farPlane : float -> float
  2419.  
  2420. // need to talk about interdependencies of these variables...
  2421. // send mail to Dan at Pixar and ask, especially about fStop, focalLength, and focalDistance...
  2422.  
  2423. - setupTraces
  2424. {
  2425.   char         *valAsString, *varName;
  2426.   RtPoint      anEyePoint, aViewPoint;
  2427.   RtFloat      aRollAngle;
  2428.  
  2429.  
  2430.   valAsString = (char *)NXZoneCalloc([self zone], 256, sizeof(char));
  2431.   varName = (char *)NXZoneCalloc([self zone], 256, sizeof(char));
  2432.  
  2433.   // need to pull out my current camera parameters and send them as
  2434.   // "set cam(paramName) paramValue" to my interp here...
  2435.   // and then we need to set up read and write traces so that any set calls
  2436.   // on any cam() variable will be in synch with this instance...
  2437.   
  2438.  
  2439.   // you may be asking yourself here: "why is wave, that bozo, copying
  2440.   // the strings that correspond to the variables names into a tmp
  2441.   // variable?  Is he really that wasteful, just because he has bigger
  2442.   // and more expensive equipment than I do?  Is he intentionally wasting
  2443.   // my precious time?"  Well, sports fans, no.  The problem is that
  2444.   // the current (7.3) implementation of tcl still uses a performance
  2445.   // hack that gets bit by compilers being smart.  The short answer is
  2446.   // if you hand tcl a const char* that the compiler has squirreled away
  2447.   // somewhere in read-only space, you will dump core, because tcl,
  2448.   // while doing a comparison on array elements, attempts to stick a '\0'
  2449.   // where the '(' is so it can do a fast hash table lookup.  It's very
  2450.   // good about taking the '\0' out once its done, but unfortunately, 
  2451.   // you'll never get the chance...  This is reasonably well documented
  2452.   // in the tcl doc, and given the efficiency, I can't really complain,
  2453.   // but it *is* a bug (whether in C, the compiler, or tcl, you make the call).
  2454.   // Anyway, to get around it, you either use the setVar2 version, or
  2455.   // you make sure that the string you hand into setVar is writable.
  2456.   // gak...
  2457.  
  2458.   // 
  2459.   strcpy(varName, "cam(fieldOfView)");
  2460.   sprintf(valAsString, "%f", [self fieldOfView]); // turn the value into its tcl equivalent
  2461.   [tclInterp setVar:varName toValue:valAsString];
  2462.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForFieldOfViewByAngle usingData:(ClientData)self];
  2463.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForFieldOfViewByAngle usingData:(ClientData)self];
  2464.  
  2465.   //
  2466.   [self getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  2467.  
  2468.   strcpy(varName, "cam(eyePoint)");
  2469.   sprintf(valAsString, "%f %f %f", N3D_XComp(anEyePoint), N3D_YComp(anEyePoint), N3D_ZComp(anEyePoint));
  2470.   [tclInterp setVar:varName toValue:valAsString];
  2471.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForEyePoint usingData:(ClientData)self];
  2472.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForEyePoint usingData:(ClientData)self];
  2473.  
  2474.   strcpy(varName, "cam(viewPoint)");
  2475.   sprintf(valAsString, "%f %f %f", N3D_XComp(aViewPoint), N3D_YComp(aViewPoint), N3D_ZComp(aViewPoint));
  2476.   [tclInterp setVar:varName toValue:valAsString];
  2477.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForViewPoint usingData:(ClientData)self];
  2478.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForViewPoint usingData:(ClientData)self];
  2479.  
  2480.   strcpy(varName, "cam(rollAngle)");
  2481.   sprintf(valAsString, "%f", aRollAngle); // turn the value into its tcl equivalent
  2482.   [tclInterp setVar:varName toValue:valAsString];
  2483.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForRollAngle usingData:(ClientData)self];
  2484.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForRollAngle usingData:(ClientData)self];
  2485.  
  2486.   // 
  2487.   strcpy(varName, "cam(fStop)");
  2488.   sprintf(valAsString, "%f", [self fStop]); // turn the value into its tcl equivalent
  2489.   [tclInterp setVar:varName toValue:valAsString];
  2490.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForFStop usingData:(ClientData)self];
  2491.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForFStop usingData:(ClientData)self];
  2492.   // 
  2493.   strcpy(varName, "cam(focalLength)");
  2494.   sprintf(valAsString, "%f", [self focalLength]); // turn the value into its tcl equivalent
  2495.   [tclInterp setVar:varName toValue:valAsString];
  2496.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForFocalLength usingData:(ClientData)self];
  2497.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForFocalLength usingData:(ClientData)self];
  2498.   // 
  2499.   strcpy(varName, "cam(focalDistance)");
  2500.   sprintf(valAsString, "%f", [self focalDistance]); // turn the value into its tcl equivalent
  2501.   [tclInterp setVar:varName toValue:valAsString];
  2502.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForFocalDistance usingData:(ClientData)self];
  2503.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForFocalDistance usingData:(ClientData)self];
  2504.   // 
  2505.   strcpy(varName, "cam(frameNumber)");
  2506.   sprintf(valAsString, "%d", [self frameNumber]); // turn the value into its tcl equivalent
  2507.   [tclInterp setVar:varName toValue:valAsString];
  2508.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForFrameNumber usingData:(ClientData)self];
  2509.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForFrameNumber usingData:(ClientData)self];
  2510.   // 
  2511.   strcpy(varName, "cam(shotLength)");
  2512.   sprintf(valAsString, "%f", [self shotLength]); // turn the value into its tcl equivalent
  2513.   [tclInterp setVar:varName toValue:valAsString];
  2514.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForShotLength usingData:(ClientData)self];
  2515.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForShotLength  usingData:(ClientData)self];
  2516.   // 
  2517.   strcpy(varName, "cam(shotStartTime)");
  2518.   sprintf(valAsString, "%f", [self shotStartTime]); // turn the value into its tcl equivalent
  2519.   [tclInterp setVar:varName toValue:valAsString];
  2520.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForShotStartTime usingData:(ClientData)self];
  2521.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForShotStartTime  usingData:(ClientData)self];
  2522.   // 
  2523.   strcpy(varName, "cam(framesPerSecond)");
  2524.   sprintf(valAsString, "%f", [self framesPerSecond]); // turn the value into its tcl equivalent
  2525.   [tclInterp setVar:varName toValue:valAsString];
  2526.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForFramesPerSecond usingData:(ClientData)self];
  2527.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForFramesPerSecond usingData:(ClientData)self];
  2528.   // 
  2529.   strcpy(varName, "cam(exposureLengthFactor)");
  2530.   sprintf(valAsString, "%f", [self exposureLengthFactor]); // turn the value into its tcl equivalent
  2531.   [tclInterp setVar:varName toValue:valAsString];
  2532.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForExposureLengthFactor usingData:(ClientData)self];
  2533.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForExposureLengthFactor usingData:(ClientData)self];
  2534.   // 
  2535.   strcpy(varName, "cam(shutterOpenTime)");
  2536.   sprintf(valAsString, "%f", [self shutterOpenTime]); // turn the value into its tcl equivalent
  2537.   [tclInterp setVar:varName toValue:valAsString];
  2538.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForShutterOpenTime usingData:(ClientData)self];
  2539.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForShutterOpenTime usingData:(ClientData)self];
  2540.   // 
  2541.   strcpy(varName, "cam(shutterCloseTime)");
  2542.   sprintf(valAsString, "%f", [self shutterCloseTime]); // turn the value into its tcl equivalent
  2543.   [tclInterp setVar:varName toValue:valAsString];
  2544.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForShutterCloseTime usingData:(ClientData)self];
  2545.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForShutterCloseTime usingData:(ClientData)self];
  2546.   // 
  2547.   strcpy(varName, "cam(exposureLength)");
  2548.   sprintf(valAsString, "%f", [self exposureLength]); // turn the value into its tcl equivalent
  2549.   [tclInterp setVar:varName toValue:valAsString];
  2550.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForExposureLength usingData:(ClientData)self];
  2551.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForExposureLength usingData:(ClientData)self];
  2552.   // 
  2553.   // 
  2554.   strcpy(varName, "cam(interpolationProc)");
  2555.   // need to set up a default interpolation proc...
  2556.   sprintf(valAsString, "noop");
  2557.   [tclInterp setVar:varName toValue:valAsString];
  2558.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForInterpolationProc usingData:(ClientData)self];
  2559.  
  2560.   // continue for all variables...
  2561.  
  2562.  
  2563.   inSynchWithTclInterp = YES;
  2564.   NXZoneFree([self zone], valAsString);
  2565.   NXZoneFree([self zone], varName);
  2566.  
  2567.  
  2568.   return self;
  2569. }
  2570.  
  2571.  
  2572. - initFrame:(const NXRect *)r 
  2573. {
  2574.    RtPoint fromP = {0,0,-5.0}, toP = {0,0,0};
  2575.    id aShape;
  2576.  
  2577.  
  2578.    [super initFrame:r];
  2579.  
  2580.    // speed stuff up and help workaround HP 3.2 bug (32 bit w/qrman crashes WS)
  2581.    [self setOpaque:YES];
  2582.  
  2583.    tclInterp = [[WWInterp alloc] init];
  2584.  
  2585.    [self initInterp];
  2586.  
  2587.    renderStyle = N3D_SmoothSolids;
  2588.    movingRenderStyle = N3D_WireFrame;
  2589.  
  2590.    scaleUpFactor = 1.05;
  2591.    scaleDownFactor = 0.95;
  2592.    translateXFactor = 0.01;
  2593.    translateYFactor = 0.01;
  2594.    translateZFactor = 0.05;
  2595.    epsilon = 4.0;
  2596.    selectionWidthEpsilon = 8.0;
  2597.    selectionHeightEpsilon = 8.0;
  2598.    shadingRate = 4.0;
  2599.    renderAtMediumRate = 1;
  2600.    renderAtHighRate = 2;
  2601.    renderCheckTimeSlice = 3.0;
  2602.    showSelectedShape = YES;
  2603.    drawOriginForSelectedShape = NO;
  2604.    
  2605.    // setup 3D camera stuff
  2606.    [self setEyeAt:fromP toward:toP roll:0.0];
  2607.  
  2608.   [self setupDefaultLights];
  2609.   otherLightList = [[List alloc] init];
  2610.  
  2611.   // setup some initial global rendering state
  2612.   [self setSurfaceTypeForAll:renderStyle chooseHider:YES];    
  2613.   lowRezTesselationVector[0] = lowRezTesselationVector[1] = 4.0;
  2614.   tesselationVector[0] = tesselationVector[1] = 16.0;
  2615.   RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, tesselationVector, RI_NULL);
  2616.  
  2617.   // stick in a reasonable shader
  2618.   theShader=[[WW3DShader alloc] init];
  2619.   [theShader setUseColor:YES];
  2620.   [theShader setColor:ribColor];
  2621.   [(N3DShader *)theShader setShader:"plastic"];
  2622.  
  2623.   // stick in a reasonable reference shape
  2624.   aShape = [[WW3DShape alloc] init];
  2625.   [aShape setShapeName:NXCopyStringBuffer("defaultTorus")];
  2626.   [aShape setShapeName:NXCopyStringBuffer("WW3DWell")];
  2627.   [aShape appendRIBCommand:[[RIBColor alloc] init]];
  2628.   //[aShape appendRIBCommand:[[RIBTorus alloc] init]];
  2629.  
  2630.   // To show off the RIBCommand archiving bug, uncomment the next
  2631.   // command, recompile, load up the WW3DPalette in IB (running IB in gdb),
  2632.   // and drag the well off the palette...
  2633.  
  2634.   [aShape appendRIBCommand:[[WW3DText alloc] initWithCharPath:"WW3DWell" 
  2635.                                    usingFont:[Font newFont:"Helvetica" 
  2636.                                        size:36] 
  2637.                                    myShape:aShape justification:NX_CENTERED]];
  2638.  
  2639.   [aShape calculateBoundingBoxStartingAt:0.0 endingAt:0.0];
  2640.  
  2641.   [aShape  setShader_:theShader];
  2642.   [[self setWorldShape:aShape] free]; // free the default world shape
  2643.   currentShape = nil;
  2644.   [self setCurrentShape:[self worldShape]];  // set current shape to be top
  2645.  
  2646.   [self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES];
  2647.  
  2648.   theRotator = [[N3DRotator alloc] initWithCamera:self];
  2649.   [theRotator setRotationAxis:N3D_AllAxes];
  2650.  
  2651.   [self setPreTransformMatrix:(RtFloat (*)[4])N3DIdentityMatrix];
  2652.   statusBufSize = 256;
  2653.   statusBuf = (char *)NXZoneCalloc([self zone], statusBufSize, sizeof(char));
  2654.  
  2655.   fStop = RI_INFINITY;  // pinhole camera
  2656.   focalLength = 50;
  2657.   focalDistance = abs((N3D_ZComp(fromP) - N3D_ZComp(toP)));
  2658.  
  2659.   shutterOpenTime = 0.0;
  2660.   framesPerSecond = 15.0;
  2661.   frameTimeIncrement = 1.0/framesPerSecond;  // start off with 15 fps
  2662.   savedExposureLength = exposureLength = frameTimeIncrement;  // start off with a motion blurred still camera
  2663.   // start off with a film-like motion picture camera
  2664.   exposureLengthFactor = .5;
  2665.   
  2666.   // shot stuff
  2667.   shotStartTime = 0.0; // begin at the beginning...
  2668.   shotLength = 3.0; // let's start off with a 3 second shot
  2669.   frameNumber = 0;
  2670.   startFrame = 0;
  2671.   endFrame =  shotLength * framesPerSecond; 
  2672.  
  2673.   [self setShooting:NO];
  2674.   justFinishedShooting = NO;
  2675.   justResetExposureLength = NO;
  2676.  
  2677.   [self setupTraces];
  2678.  
  2679.   return self;
  2680. }
  2681.  
  2682. // the receptor gets sent this message when the object is dragged into
  2683. // the File window, and when it is unarchived from the nib file.
  2684. - awake
  2685. {
  2686.   [super awake];
  2687.  
  2688.   // everything else has just been unarchived...
  2689.  
  2690.   [self initInterp];
  2691.   theRotator = [[N3DRotator alloc] initWithCamera:self];
  2692.   [theRotator setRotationAxis:N3D_AllAxes];
  2693.  
  2694.   RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, tesselationVector, RI_NULL);
  2695.  
  2696.   currentShape = nil;
  2697.   [self setCurrentShape:[self worldShape]];  // set current shape to be top
  2698.  
  2699.   statusBufSize = 256;
  2700.   statusBuf = (char *)NXZoneCalloc([self zone], statusBufSize, sizeof(char));
  2701.  
  2702.   frameTimeIncrement = 1.0/framesPerSecond;
  2703.   savedExposureLength = exposureLength;
  2704.   justFinishedShooting = NO;
  2705.   justResetExposureLength = NO;
  2706.  
  2707.   [self setupTraces];
  2708.  
  2709.   return self;
  2710. }
  2711.  
  2712. - free
  2713.  
  2714. {
  2715.   if (statusBuf) { NXZoneFree([self zone], statusBuf); }
  2716.   [self removeAnimateTE];
  2717.   [self removeRenderTE];
  2718.  
  2719.   [super free];
  2720.  
  2721.   // make sure you free the tcl interp after the rootShape, because
  2722.   // EveCommands that get free'd will want to untrace their corresponding
  2723.   // tcl variables, and we don't want them sending messages to an already
  2724.   // free'd tclInterp
  2725.  
  2726.   [tclInterp free];
  2727.  
  2728.   self = nil;
  2729.   return self;
  2730. }
  2731.  
  2732.  
  2733. - synchToSceneClock:aSceneClock
  2734. {
  2735.   float  sceneTime = [aSceneClock timestamp];
  2736.  
  2737.  
  2738.   // the idea here is to advance to the first frame that shows the scene's time.
  2739.   [self setFrameNumber:(int)(sceneTime * framesPerSecond)];
  2740.   [self display];
  2741.   return self;
  2742. }
  2743.  
  2744.  
  2745. - dumpCameraStateTo:(const char *)camName
  2746. {
  2747.   char         *valAsString, *varName;
  2748.   RtPoint      anEyePoint, aViewPoint;
  2749.   RtFloat      aRollAngle;
  2750.  
  2751.  
  2752.   valAsString = (char *)NXZoneCalloc([self zone], 256, sizeof(char));
  2753.   varName = (char *)NXZoneCalloc([self zone], 256, sizeof(char));
  2754.  
  2755.   // need to pull out my current camera parameters and send them as
  2756.   // "set camName(paramName) paramValue" to my interp here...
  2757.   // and then we need to set up write traces so that any set calls fail
  2758.  
  2759.   // 
  2760.   sprintf(varName, "%s(fieldOfView)", camName);
  2761.   sprintf(valAsString, "%f", [self fieldOfView]); // turn the value into its tcl equivalent
  2762.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  2763.   //
  2764.   [self getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  2765.  
  2766.   sprintf(varName, "%s(eyePoint)", camName);
  2767.   sprintf(valAsString, "%f %f %f", N3D_XComp(anEyePoint), N3D_YComp(anEyePoint), N3D_ZComp(anEyePoint));
  2768.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  2769.  
  2770.   sprintf(varName, "%s(viewPoint)", camName);
  2771.   sprintf(valAsString, "%f %f %f", N3D_XComp(aViewPoint), N3D_YComp(aViewPoint), N3D_ZComp(aViewPoint));
  2772.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  2773.  
  2774.   sprintf(varName, "%s(rollAngle)", camName);
  2775.   sprintf(valAsString, "%f", aRollAngle); // turn the value into its tcl equivalent
  2776.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  2777.   // 
  2778.   sprintf(varName, "%s(fStop)", camName);
  2779.   sprintf(valAsString, "%f", [self fStop]); // turn the value into its tcl equivalent
  2780.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  2781.   // 
  2782.   sprintf(varName, "%s(focalLength)", camName);
  2783.   sprintf(valAsString, "%f", [self focalLength]); // turn the value into its tcl equivalent
  2784.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  2785.   // 
  2786.   sprintf(varName, "%s(focalDistance)", camName);
  2787.   sprintf(valAsString, "%f", [self focalDistance]); // turn the value into its tcl equivalent
  2788.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  2789.   // 
  2790.   sprintf(varName, "%s(frameNumber)", camName);
  2791.   sprintf(valAsString, "%d", [self frameNumber]); // turn the value into its tcl equivalent
  2792.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  2793.   // 
  2794.   sprintf(varName, "%s(shutterOpenTime)", camName);
  2795.   sprintf(valAsString, "%f", [self shutterOpenTime]); // turn the value into its tcl equivalent
  2796.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  2797.   // 
  2798.   sprintf(varName, "%s(shutterCloseTime)", camName);
  2799.   sprintf(valAsString, "%f", [self shutterCloseTime]); // turn the value into its tcl equivalent
  2800.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  2801.   // 
  2802.   sprintf(varName, "%s(frameTimeIncrement)", camName);
  2803.   sprintf(valAsString, "%f", [self frameTimeIncrement]); // turn the value into its tcl equivalent
  2804.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  2805.   // 
  2806.   sprintf(varName, "%s(exposureLength)", camName);
  2807.   sprintf(valAsString, "%f", [self exposureLength]); // turn the value into its tcl equivalent
  2808.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  2809.   // 
  2810.  
  2811.   NXZoneFree([self zone], valAsString);
  2812.   NXZoneFree([self zone], varName);
  2813.  
  2814.   return self;
  2815. }
  2816.  
  2817.  
  2818. - evaluateCameraInterpolationRoutineWith:(float)u
  2819. {
  2820.    char   cmd[80];
  2821.  
  2822.  
  2823.    sprintf(cmd, "eval $cam(interpolationProc) %f", u);
  2824.    //NXLogError("WW3DCamera's interp evaluating camera interpolation routine with %f for frame number %d here...\n", 
  2825.    //          u, [self frameNumber]);
  2826.    [tclInterp globalEval:cmd];
  2827.    return self;
  2828. }
  2829.  
  2830.  
  2831. - worldBegin:(RtToken)context
  2832. {
  2833.    RtInt   jitterFlag = 1;
  2834.    float   u;
  2835.    static  RtInt v31 = 301;
  2836.    int     theFrameNumber;
  2837.  
  2838.  
  2839.    if (dumpingToRIB)
  2840.    {  RiOption(RI_ARCHIVE, "outputversion", &v31, RI_NULL);
  2841.       NXLogError("boy, I'm wicked compatible...\n");
  2842.    }
  2843.    RiImager("clamptoalpha", RI_NULL);
  2844.  
  2845.    // Run camera interpolation procedure here. We do it here (as opposed
  2846.    // to doing it in drawSelf:), because at this point, all the camera
  2847.    // parameters are as fixed as they're gonna get for this frame.
  2848.  
  2849.    // when a new frame number is set with setFrameNumber:, it sets the 
  2850.    // BOOL evaluateInterpProc.  We only want to run this proc once per
  2851.    // frame, but we also don't want to do it until this point.  So...
  2852.    // at this point, if the flag is set, we evaluate the proc with
  2853.    // the current value of u.
  2854.    // note that if the currentFrame == startFrame, and the flag is set,
  2855.    // we need to do some initial work to set up the state.  We need to
  2856.    // fill out the global tcl array startCam(), which is to have the state 
  2857.    // of the current camera in read-only variables...
  2858.  
  2859.    if (shooting)
  2860.    {  theFrameNumber = [self frameNumber];
  2861.  
  2862.       if (theFrameNumber == 0) // sanity check!
  2863.       {  savedExposureLength = exposureLength; 
  2864.          [self setExposureLength:([self frameTimeIncrement] * exposureLengthFactor)];
  2865.       }
  2866.       if (evaluateInterpProc)
  2867.       {  if (theFrameNumber == 0) 
  2868.          {  // initialize startCam() array with my current state 
  2869.             [tclInterp unsetVar:"startCam"];
  2870.             [self dumpCameraStateTo:"startCam"];  
  2871.             u = 0;
  2872.          } 
  2873.          else
  2874.          {  // calculate u, where u is 0 at startFrame and 1 at endFrame
  2875.             // let's say startFrame is 0, endFrame is 100, and frameNumber is 25
  2876.             // we want u to be .25
  2877.             // note that we should not have to worry about div by zero here...
  2878.             u = (float)theFrameNumber/(float)([self endFrame] - 1);
  2879.          }
  2880.          [self evaluateCameraInterpolationRoutineWith:u];
  2881.          evaluateInterpProc = NO;
  2882.       }
  2883.    }
  2884.    else  // if we're not shooting, we want the camera to be in synch with the scene clock and be a strobe camera...
  2885.    {  // ask the sceneClock what time it is, and make ourselves a strobe camera
  2886.       if (justFinishedShooting) // when we come out of a shot, reset the exposureLength to what it was previously
  2887.       {  [self setExposureLength:savedExposureLength]; // need to do it "correctly", so tcl is notified
  2888.          justFinishedShooting = NO;
  2889.       }
  2890.       [self setShutterOpenTime:[sceneClock timestamp]];  // need to do it "correctly", so tcl is notified
  2891.    }
  2892.  
  2893.    // If I want to support depth-of-field, need to call RiDepthOfField()
  2894.    RiDepthOfField(fStop, focalLength, focalDistance);
  2895.    // If I want to support motion blur, need to call RiShutter(), as well 
  2896.    // as having  RiMotionBegin/End blocks around primitives
  2897.    RiShutter(shutterOpenTime, (shutterOpenTime + (exposureLength * exposureLengthFactor)));
  2898.    if (exposureLength > 0.0)  // is it a strobe or not?
  2899.    {  // optimize for motion blur...
  2900.       // should make these variables, dude...     
  2901.       RiPixelSamples(3.0, 3.0);
  2902.       // really should find out what the hider has been set to...
  2903.       RiHider("hidden", "jitter", &jitterFlag, RI_NULL);
  2904.    }
  2905.  
  2906.    // or whatever the heck is the right thang...
  2907.    if (renderCount == renderAtMediumRate)
  2908.    {  RiShadingRate(50.0);
  2909.    } 
  2910.    else
  2911.    {  if (renderCount == renderAtHighRate)
  2912.       {  RiShadingRate(5.0);
  2913.       }
  2914.    }
  2915.  
  2916.    [super worldBegin:context];
  2917.    return self;
  2918. }
  2919.  
  2920. - getTransformMatrix:(RtMatrix)aMatrix
  2921. {
  2922.   N3D_CopyMatrix(transform, aMatrix);
  2923.   return self;
  2924. }
  2925.  
  2926. - takeStatusText:sender  { statusText = sender; return self; }
  2927.  
  2928. - delegate { return delegate; }
  2929.  
  2930. /////////////////////// 
  2931. // 3D stuff
  2932. /////////////////////// 
  2933. - setNoCurrentShape:sender { currentShape = nil; return self; }
  2934.  
  2935. - currentShape { return currentShape; }
  2936. - setCurrentShape:newCurrentShape
  2937. {
  2938.   // should make sure newShape is a child of worldShape...
  2939.   [currentShape setSelected:NO andDrawOrigin:NO];
  2940.   currentShape = newCurrentShape;
  2941.   [currentShape setSelected:showSelectedShape andDrawOrigin:drawOriginForSelectedShape];
  2942.   
  2943.   // WAVE this is expensive; I should have a flag...
  2944.   //[self display];
  2945.  
  2946.   if (statusText) // potentially record activity
  2947.   {  sprintf(statusBuf, "currentShape is: %s", [currentShape shapeName]);
  2948.      [statusText setStringValue:statusBuf];
  2949.   }
  2950.  
  2951.   return self;
  2952. }
  2953.  
  2954. - (RtFloat)tesselation { return tesselationVector[0]; }
  2955.  
  2956. - takeTesselation:sender
  2957. {
  2958.   tesselationVector[0] = tesselationVector[1] = [sender floatValue];
  2959.   RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, tesselationVector, RI_NULL);
  2960.  
  2961.   if (statusText) // potentially record activity
  2962.   {  sprintf(statusBuf, "tesselation set to (%f %f)", 
  2963.          tesselationVector[0], tesselationVector[1]);
  2964.      [statusText setStringValue:statusBuf];
  2965.   }
  2966.  
  2967.   [self display];
  2968.  
  2969.   return self;
  2970. }
  2971.  
  2972. - (RtFloat)lowRezTesselation { return lowRezTesselationVector[0]; }
  2973.  
  2974. - takeLowRezTesselation:sender
  2975. {
  2976.   lowRezTesselationVector[0] = lowRezTesselationVector[1] = [sender floatValue];
  2977.   if (statusText) // potentially record activity
  2978.   {  sprintf(statusBuf, "low rez tesselation set to (%f %f)", 
  2979.          lowRezTesselationVector[0], lowRezTesselationVector[1]);
  2980.      [statusText setStringValue:statusBuf];
  2981.   }
  2982.   return self;
  2983. }
  2984.  
  2985. - (float)shadingRate { return shadingRate; }
  2986. - takeShadingRate:sender
  2987. {
  2988.   shadingRate = [sender floatValue];
  2989.   if (shadingRate < 0.25)
  2990.   {  shadingRate = 0.25;
  2991.   }
  2992.   if (shadingRate > 100.0)
  2993.   {  shadingRate = 100.0;
  2994.   }
  2995.   return self;
  2996. }
  2997.  
  2998. - takeAmbientLightState:sender
  2999. {
  3000.    [ambientLight switchLight:[sender intValue]];
  3001.    return [self display];
  3002. }
  3003. - takeAmbientLightIntensity:sender
  3004. {
  3005.    [ambientLight setIntensity:[sender floatValue]];
  3006.    return [self display];
  3007. }
  3008. - takeAmbientLightColor:sender
  3009. {
  3010.    [ambientLight setColor:[sender color]];
  3011.    return [self display];
  3012. }
  3013. - takeLeftLightState:sender
  3014. {
  3015.    [leftLight switchLight:[sender intValue]];
  3016.    return [self display];
  3017. }
  3018. - takeLeftLightIntensity:sender
  3019. {
  3020.    [leftLight setIntensity:[sender floatValue]];
  3021.    return [self display];
  3022. }
  3023. - takeLeftLightColor:sender
  3024. {
  3025.    [leftLight setColor:[sender color]];
  3026.    return [self display];
  3027. }
  3028. - takeRightLightState:sender
  3029. {
  3030.    [rightLight switchLight:[sender intValue]];
  3031.    return [self display];
  3032. }
  3033. - takeRightLightIntensity:sender
  3034. {
  3035.    [rightLight setIntensity:[sender floatValue]];
  3036.    return [self display];
  3037. }
  3038. - takeRightLightColor:sender
  3039. {
  3040.    [rightLight setColor:[sender color]];
  3041.    return [self display];
  3042. }
  3043.  
  3044. - (BOOL)ambientLightState { return [ambientLight on]; }
  3045. - (RtFloat)ambientLightIntensity { return [ambientLight intensity]; }
  3046. - (NXColor)ambientLightColor { return [ambientLight color]; }
  3047.  
  3048. - (BOOL)leftLightState { return [leftLight on]; }
  3049. - (RtFloat)leftLightIntensity { return [leftLight intensity]; }
  3050. - (NXColor)leftLightColor { return [leftLight color]; }
  3051.  
  3052. - (BOOL)rightLightState { return [rightLight on]; }
  3053. - (RtFloat)rightLightIntensity { return [ rightLight intensity]; }
  3054. - (NXColor)rightLightColor { return [rightLight color]; }
  3055.  
  3056. - saveImage:sender
  3057. {
  3058.   static id savePanel=nil;
  3059.   NXStream *ts;
  3060.  
  3061.  
  3062.   if (!savePanel) 
  3063.   {  savePanel=[SavePanel new];
  3064.   }
  3065.  
  3066.   [savePanel setRequiredFileType:"tiff"];
  3067.   if([savePanel runModal])
  3068.   {  ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  3069.      [image writeTIFF:ts allRepresentations:NO usingCompression:NX_TIFF_COMPRESSION_LZW andFactor:1.0];
  3070.      NXSaveToFile(ts, [savePanel filename]);
  3071.      NXCloseMemory(ts,NX_FREEBUFFER);
  3072.   }
  3073.  
  3074.   return self;
  3075. }
  3076.  
  3077.  
  3078. - dumpRIB:sender
  3079. {
  3080.   static id savePanel=nil;
  3081.   NXStream *ts;
  3082.   char filename[MAXPATHLEN+1];
  3083.  
  3084.  
  3085.   if (statusText) // potentially record activity
  3086.   {  sprintf(statusBuf, "dumping RIB...");
  3087.      [statusText setStringValue:statusBuf];
  3088.   }
  3089.  
  3090.   if (!savePanel) 
  3091.   {  savePanel=[SavePanel new];
  3092.      [savePanel setRequiredFileType:"rib"];
  3093.   }
  3094.  
  3095.   if([savePanel runModal])
  3096.   {  // returned w/pathname, open a stream and
  3097.      ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  3098.  
  3099.      // remove the .rib extension from the path returned by the SavePanel
  3100.      basename([savePanel filename], ".rib", filename);
  3101.  
  3102.      // feed to NXPrintf to put in the custom Display command
  3103.      NXPrintf(ts, "# This RIB file generated by Michael B. Johnson's WW3DKit software running under NeXTSTEP.\n");
  3104.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 547-0563 for more information.\n#\n");
  3105.      NXPrintf(ts, "Display \"%s.tiff\" \"file\" \"rgba\"\n", filename);
  3106.      NXPrintf(ts, "ShadingRate %f\n", shadingRate);
  3107.  
  3108.      // then feed the rib code to the stream and
  3109.      [self copyRIBCode:ts];
  3110.      // save the stream to the file selected in the savepanel
  3111.      NXSaveToFile(ts, [savePanel filename]);
  3112.  
  3113.      // and close the stream (which also flushes it), also making sure
  3114.      // that the allocated memory is freed.
  3115.     NXCloseMemory(ts,NX_FREEBUFFER);
  3116.   }
  3117.  
  3118.   if (statusText) // potentially record activity
  3119.   {  sprintf(statusBuf, "done!");
  3120.      [statusText setStringValue:statusBuf];
  3121.   }
  3122.   return self;
  3123. }
  3124.  
  3125. - copyRIBCode:(NXStream *)ts
  3126. {
  3127.   id retID, tmpText = statusText;
  3128.  
  3129.  
  3130.   sprintf(statusBuf, "disabling status display to avoid NeXT's copyRIBCode: bug...");
  3131.   [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  3132.   statusText = nil;
  3133.   retID = [super copyRIBCode:ts];
  3134.   statusText = tmpText;
  3135.   return retID;
  3136. }
  3137.  
  3138.  
  3139. - dumpShotToRIBFile:(const char *)longFilename
  3140. {
  3141.   NXStream   *ts;
  3142.   char       filename[MAXPATHLEN+1];
  3143.   int        oldFrameNumber, i, startI, endI, incI;
  3144.   static id  savePanel=nil;
  3145.  
  3146.  
  3147.   if (statusText) // potentially record activity
  3148.   {  sprintf(statusBuf, "dumping complete shot to RIB file %s...", longFilename);
  3149.      [statusText setStringValue:statusBuf];
  3150.   }
  3151.  
  3152.   // make sure it's a RIB file (at least 1.rib)...
  3153.   if (longFilename && (strlen(longFilename) > 4) && (!strcmp(".rib", (const char *)(longFilename + strlen(longFilename) - 4))))
  3154.   {  // returned w/pathname, open a stream and
  3155.      ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  3156.  
  3157.      // remove the .rib extension from the path returned by the SavePanel
  3158.      basename(longFilename, ".rib", filename);
  3159.  
  3160.      // feed to NXPrintf to put in the custom Display command
  3161.      NXPrintf(ts, "# This RIB file generated by Michael B. Johnson's WW3DKit software running under NeXTSTEP.\n");
  3162.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 547-0563 for more information.\n#\n");
  3163.  
  3164.  
  3165.      // we need to loop over the whole shot, starting at the first frame, and incrementing correctly.
  3166.      // The 3DKit will take care of putting in frame numbers, but we need to manage the names of the 
  3167.      // tiff files that will get saved out. The WWAnimatable and WWRenderable objects that this camera
  3168.      // is attached to will take care of figuring out what time it is when the camera takes their picture.
  3169.  
  3170.      NXPrintf(ts, "ShadingRate %f\n", shadingRate);
  3171.      
  3172.      oldFrameNumber = [self frameNumber];
  3173.      startI = [self startFrame];
  3174.      endI = [self endFrame];
  3175.      incI = [self frameIncrement];
  3176.  
  3177.      // due to a bug in NeXT's 3DKit, we want to make sure that
  3178.      // nothing gets written out to a view while we're in
  3179.      // "copyRIBCode:". Unfortunately, that's pretty hard...  The most likely
  3180.      // culprit is a routine (like the current camera's interpolation routine)
  3181.      // writing out to the "statusText" outlet.  Probably the best thing to do
  3182.      // then is to save the value of that outlet and set it to nil for the
  3183.      // duration of copyRIBCode:...  actually, the better thing to do is
  3184.      // probably reimplement copyRIBCode:, where I unset the outlet, call
  3185.      // the super's version, and then set it back.  Yea, let's try that...
  3186.  
  3187.      shooting = YES;
  3188.      [self setFrameNumber:(startI - 1)]; // just to flush state...
  3189.      for (i = startI; i < endI; i += incI)
  3190.      {  [self setFrameNumber:i]; 
  3191.         NXPrintf(ts, "Display \"%s.%d.tiff\" \"file\" \"rgba\"\n", filename, i);
  3192.         [self copyRIBCode:ts];
  3193.      }
  3194.      NXSaveToFile(ts, [savePanel filename]);
  3195.      NXCloseMemory(ts,NX_FREEBUFFER);
  3196.  
  3197.      [self setFrameNumber:oldFrameNumber];
  3198.      shooting = NO;
  3199.   }
  3200.   else
  3201.   {  sprintf(statusBuf, "<%s> is not a valid filename for a RIB file.\n", longFilename);
  3202.      [statusText setStringValue:statusBuf];
  3203.      return nil;
  3204.   }
  3205.   if (statusText) // potentially record activity
  3206.   {  sprintf(statusBuf, "done!");
  3207.      [statusText setStringValue:statusBuf];
  3208.   }
  3209.   return self;
  3210. }
  3211.  
  3212.  
  3213. - dumpShotToRIB:sender
  3214. {
  3215.   static id  savePanel=nil;
  3216.   NXStream   *ts;
  3217.   char       filename[MAXPATHLEN+1];
  3218.   int        oldFrameNumber, i, startI, endI, incI;
  3219.  
  3220.  
  3221.   if (statusText) // potentially record activity
  3222.   {  sprintf(statusBuf, "dumping complete shot to RIB...");
  3223.      [statusText setStringValue:statusBuf];
  3224.   }
  3225.  
  3226.   if (!savePanel) 
  3227.   {  savePanel=[SavePanel new];
  3228.      [savePanel setRequiredFileType:"rib"];
  3229.   }
  3230.  
  3231.   if([savePanel runModal])
  3232.   {  // returned w/pathname, open a stream and
  3233.      ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  3234.  
  3235.      // remove the .rib extension from the path returned by the SavePanel
  3236.      basename([savePanel filename], ".rib", filename);
  3237.  
  3238.      // feed to NXPrintf to put in the custom Display command
  3239.      NXPrintf(ts, "# This RIB file generated by Michael B. Johnson's WW3DKit software running under NeXTSTEP.\n");
  3240.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 547-0563 for more information.\n#\n");
  3241.  
  3242.  
  3243.      // we need to loop over the whole shot, starting at the first frame, and incrementing correctly.
  3244.      // The 3DKit will take care of putting in frame numbers, but we need to manage the names of the 
  3245.      // tiff files that will get saved out. The WWAnimatable and WWRenderable objects that this camera
  3246.      // is attached to will take care of figuring out what time it is when the camera takes their picture.
  3247.  
  3248.      NXPrintf(ts, "ShadingRate %f\n", shadingRate);
  3249.      
  3250.      oldFrameNumber = [self frameNumber];
  3251.      startI = [self startFrame];
  3252.      endI = [self endFrame];
  3253.      incI = [self frameIncrement];
  3254.  
  3255.      // due to a bug in NeXT's 3DKit, we want to make sure that
  3256.      // nothing gets written out to a view while we're in
  3257.      // "copyRIBCode:". Unfortunately, that's pretty hard...  The most likely
  3258.      // culprit is a routine (like the current camera's interpolation routine)
  3259.      // writing out to the "statusText" outlet.  Probably the best thing to do
  3260.      // then is to save the value of that outlet and set it to nil for the
  3261.      // duration of copyRIBCode:...  actually, the better thing to do is
  3262.      // probably reimplement copyRIBCode:, where I unset the outlet, call
  3263.      // the super's version, and then set it back.  Yea, let's try that...
  3264.  
  3265.      shooting = YES;
  3266.      [self setFrameNumber:(startI - 1)]; // just to flush state...
  3267.      for (i = startI; i < endI; i += incI)
  3268.      {  [self setFrameNumber:i]; 
  3269.         NXPrintf(ts, "Display \"%s.%d.tiff\" \"file\" \"rgba\"\n", filename, i);
  3270.         [self copyRIBCode:ts];
  3271.      }
  3272.      NXSaveToFile(ts, [savePanel filename]);
  3273.      NXCloseMemory(ts,NX_FREEBUFFER);
  3274.  
  3275.      [self setFrameNumber:oldFrameNumber];
  3276.      shooting = NO;
  3277.   }
  3278.  
  3279.   if (statusText) // potentially record activity
  3280.   {  sprintf(statusBuf, "done!");
  3281.      [statusText setStringValue:statusBuf];
  3282.   }
  3283.   return self;
  3284. }
  3285.  
  3286.  
  3287. - dumpShotToRIBAndEveScene:sender
  3288. {
  3289.   static id  savePanel=nil;
  3290.   NXStream   *ts;
  3291.   char       filename[MAXPATHLEN+1];
  3292.   int        oldFrameNumber, i, startI, endI, incI;
  3293.   float      theShotDuration;
  3294.  
  3295.  
  3296.   if (statusText) // potentially record activity
  3297.   {  sprintf(statusBuf, "dumping complete shot to RIB...");
  3298.      [statusText setStringValue:statusBuf];
  3299.   }
  3300.  
  3301.   if (!savePanel) 
  3302.   {  savePanel=[SavePanel new];
  3303.      [savePanel setRequiredFileType:"rib"];
  3304.   }
  3305.  
  3306.   if([savePanel runModal])
  3307.   {  // returned w/pathname, open a stream and
  3308.      ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  3309.  
  3310.      // remove the .rib extension from the path returned by the SavePanel
  3311.      basename([savePanel filename], ".rib", filename);
  3312.  
  3313.      // feed to NXPrintf to put in the custom Display command
  3314.      NXPrintf(ts, "# This RIB file generated by Michael B. Johnson's WW3DKit software running under NeXTSTEP.\n");
  3315.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 547-0563 for more information.\n#\n");
  3316.  
  3317.  
  3318.      // we need to loop over the whole shot, starting at the first frame, and incrementing correctly.
  3319.      // The 3DKit will take care of putting in frame numbers, but we need to manage the names of the 
  3320.      // tiff files that will get saved out. The WWAnimatable and WWRenderable objects that this camera
  3321.      // is attached to will take care of figuring out what time it is when the camera takes their picture.
  3322.  
  3323.      NXPrintf(ts, "ShadingRate %f\n", shadingRate);
  3324.      
  3325.      oldFrameNumber = [self frameNumber];
  3326.      startI = [self startFrame];
  3327.      endI = [self endFrame];
  3328.      incI = [self frameIncrement];
  3329.  
  3330.      // due to a bug in NeXT's 3DKit, we want to make sure that
  3331.      // nothing gets written out to a view while we're in
  3332.      // "copyRIBCode:". Unfortunately, that's pretty hard...  The most likely
  3333.      // culprit is a routine (like the current camera's interpolation routine)
  3334.      // writing out to the "statusText" outlet.  Probably the best thing to do
  3335.      // then is to save the value of that outlet and set it to nil for the
  3336.      // duration of copyRIBCode:...  actually, the better thing to do is
  3337.      // probably reimplement copyRIBCode:, where I unset the outlet, call
  3338.      // the super's version, and then set it back.  Yea, let's try that...
  3339.  
  3340.      shooting = YES;
  3341.      [self setFrameNumber:(startI - 1)]; // just to flush state...
  3342.      for (i = startI; i < endI; i += incI)
  3343.      {  [self setFrameNumber:i]; 
  3344.         NXPrintf(ts, "Display \"%s.%d.tiff\" \"file\" \"rgba\"\n", filename, i);
  3345.         [self copyRIBCode:ts];
  3346.      }
  3347.      NXSaveToFile(ts, [savePanel filename]);
  3348.      NXCloseMemory(ts,NX_FREEBUFFER);
  3349.  
  3350.      [self setFrameNumber:oldFrameNumber];
  3351.      shooting = NO;
  3352.   }
  3353.  
  3354.   if (statusText) // potentially record activity
  3355.   {  sprintf(statusBuf, "done writing RIB!");
  3356.      [statusText setStringValue:statusBuf];
  3357.   }
  3358.  
  3359.   if (statusText) // potentially record activity
  3360.   {  sprintf(statusBuf, "building scene visualizing shot...");
  3361.      [statusText setStringValue:statusBuf];
  3362.   }
  3363.  
  3364.   // first determine how long the shot is:
  3365.   theShotDuration = ([self endFrame] - [self startFrame]) * [self frameIncrement];
  3366.  
  3367.   // now open a stream to write the eve file out to
  3368.   ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  3369.  
  3370.   NXPrintf(ts, "# This eve scene file visualizes the shot %s\n", [savePanel filename]);
  3371.  
  3372.   return self;
  3373. }
  3374.  
  3375.  
  3376. - dumpEve:sender
  3377. {
  3378.   static id savePanel=nil;
  3379.   NXStream *ts;
  3380.  
  3381.  
  3382.   if (statusText) // potentially record activity
  3383.   {  sprintf(statusBuf, "dumping Eve...");
  3384.      [statusText setStringValue:statusBuf];
  3385.   }
  3386.  
  3387.   if (!savePanel) 
  3388.   {  savePanel=[SavePanel new];
  3389.      [savePanel setRequiredFileType:"eve"];
  3390.   }
  3391.  
  3392.   if([savePanel runModal])
  3393.   {  // returned w/pathname, open a stream and
  3394.      ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  3395.  
  3396.      // feed to NXPrintf to put in the custom Display command
  3397.      NXPrintf(ts, "# This eve model file generated by Michael B. Johnson's WW3DKit software running under NeXTSTEP.\n");
  3398.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 547-0563 for more information.\n#\n");
  3399.  
  3400.      [[worldShape tclInterp] writeState:ts];
  3401.  
  3402.      // then tell the worldShape to write itself out, which will recurse down...
  3403.      [worldShape writeEve:ts atTabLevel:0];
  3404.  
  3405.      // save the stream to the file selected in the savepanel
  3406.      NXSaveToFile(ts, [savePanel filename]);
  3407.  
  3408.      // and close the stream (which also flushes it), also making sure
  3409.      // that the allocated memory is freed.
  3410.     NXCloseMemory(ts,NX_FREEBUFFER);
  3411.   }
  3412.  
  3413.   if (statusText) // potentially record activity
  3414.   {  sprintf(statusBuf, "done!");
  3415.      [statusText setStringValue:statusBuf];
  3416.   }
  3417.   return self;
  3418. }
  3419.  
  3420.  
  3421. - dumpScene:sender
  3422. {
  3423.   static id savePanel=nil;
  3424.   NXStream *ts;
  3425.  
  3426.  
  3427.   if (statusText) // potentially record activity
  3428.   {  sprintf(statusBuf, "dumping scene...");
  3429.      [statusText setStringValue:statusBuf];
  3430.   }
  3431.  
  3432.   if (!savePanel) 
  3433.   {  savePanel=[SavePanel new];
  3434.      [savePanel setRequiredFileType:"eve"];
  3435.   }
  3436.  
  3437.   if([savePanel runModal])
  3438.   {  // returned w/pathname, open a stream and
  3439.      ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  3440.  
  3441.      NXPrintf(ts, "#\n");
  3442.      NXPrintf(ts, "# This eve scene file generated by Michael B. Johnson's WW3DKit software running under NeXTSTEP.\n");
  3443.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 547-0563 for more information.\n#\n");
  3444.  
  3445.      [[worldShape tclInterp] writeState:ts];
  3446.  
  3447.      // then tell the worldShape to write itself out, which will recurse down...
  3448.      [worldShape writeScene:ts atTabLevel:0];
  3449.  
  3450.      // save the stream to the file selected in the savepanel
  3451.      NXSaveToFile(ts, [savePanel filename]);
  3452.  
  3453.      // and close the stream (which also flushes it), also making sure
  3454.      // that the allocated memory is freed.
  3455.     NXCloseMemory(ts,NX_FREEBUFFER);
  3456.   }
  3457.  
  3458.   if (statusText) // potentially record activity
  3459.   {  sprintf(statusBuf, "done!");
  3460.      [statusText setStringValue:statusBuf];
  3461.   }
  3462.   return self;
  3463. }
  3464.  
  3465.  
  3466. - turnOffCropWindow
  3467.    selectionRegion.size.width = 0.0;
  3468.    selectionRegion.size.height = 0.0;
  3469.    return self;
  3470. }
  3471.  
  3472. - dumpRIBToFile:(char *)filename usingShadingRate:(float)sRate hider:(char *)hiderName pixelSamples:(float)pixelSampleX :(float)pixelSampleY
  3473. {
  3474.   NXStream  *ts;
  3475.   NXRect    myFrame;
  3476.   char      buf[MAXPATHLEN+1];
  3477.   float     cropMinX, cropMinY, cropMaxX, cropMaxY;
  3478.  
  3479.  
  3480.   if (statusText) // potentially record activity
  3481.   {  sprintf(statusBuf, "dumping RIB to file %s...", filename);
  3482.      [statusText setStringValue:statusBuf];
  3483.   }
  3484.  
  3485.   ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  3486.  
  3487.   // process the file name for a custom display line such that
  3488.   // "prman <<filename>>.rib" will put the resulting image somewhere
  3489.   // predictably useful.
  3490.   strcpy(buf, filename);
  3491.  
  3492.   // remove the .rib extension from the path returned by the SavePanel
  3493.   strrchr(buf,'.')[0]='\0';
  3494.  
  3495.   // feed to NXPrintf to put in the custom Display command
  3496.   NXPrintf(ts, "# This RIB file generated by Michael B. Johnson's WW3DKit software running under NeXTSTEP.\n");
  3497.   NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 547-0563 for more information.\n#\n");
  3498.   NXPrintf(ts, "Display \"%s.tiff\" \"file\" \"rgba\"\n", buf);
  3499.   NXPrintf(ts, "ShadingRate %f\n", sRate);
  3500.   NXPrintf(ts, "Hider \"%s\"\n", hiderName);
  3501.   NXPrintf(ts, "PixelSamples %f %f\n", pixelSampleX, pixelSampleY);
  3502.   [self getFrame:&myFrame];
  3503.  
  3504.   if ((selectionRegion.size.width > selectionWidthEpsilon)||(selectionRegion.size.height > selectionHeightEpsilon))
  3505.   {  NXLogError("\n\nselectionRegion.origin == (%f, %f)\t\tselectionRegion.size == (%f, %f)\n", 
  3506.         selectionRegion.origin.x, selectionRegion.origin.y, 
  3507.         selectionRegion.size.width, selectionRegion.size.height);
  3508.      NXLogError("myFrame.origin         == (%f, %f)\t\tmyFrame.size         == (%f, %f)\n", 
  3509.         myFrame.origin.x, myFrame.origin.y, 
  3510.         myFrame.size.width, myFrame.size.height);
  3511.      //////// X //////////
  3512.      if (selectionRegion.origin.x < 0.0)
  3513.      {  cropMinX = 0.0;
  3514.      }
  3515.      else
  3516.      {  cropMinX = selectionRegion.origin.x/myFrame.size.width;
  3517.      }
  3518.  
  3519.      if ((selectionRegion.size.width + selectionRegion.origin.x) > myFrame.size.width)
  3520.      {  cropMaxX = 1.0;
  3521.      }
  3522.      else
  3523.      {  cropMaxX = (selectionRegion.size.width + selectionRegion.origin.x)/myFrame.size.width;
  3524.      }
  3525.  
  3526.      //////// Y (note Y is flipped) //////////
  3527.      if (selectionRegion.origin.y < 0.0)
  3528.      {  cropMaxY = 1.0;
  3529.      }
  3530.      else
  3531.      {  cropMaxY = 1.0 - (selectionRegion.origin.y/myFrame.size.width);
  3532.      }
  3533.  
  3534.      if ((selectionRegion.size.height + selectionRegion.origin.y) > myFrame.size.height)
  3535.      {  cropMinY = 0.0;
  3536.      }
  3537.      else
  3538.      {  cropMinY = 1.0 - ((selectionRegion.size.height + selectionRegion.origin.y)/myFrame.size.height);
  3539.      }
  3540.  
  3541.      NXLogError("CropWindow %f %f %f %f\n", cropMinX, cropMaxX, cropMinY, cropMaxY); 
  3542.  
  3543.      if (cropMinX < 0.0) { cropMinX = 0.0; } 
  3544.      if (cropMinY < 0.0) { cropMinY = 0.0; } 
  3545.      if (cropMaxX > 1.0) { cropMaxX = 1.0; } 
  3546.      if (cropMaxY > 1.0) { cropMaxY = 1.0; } 
  3547.  
  3548.      NXPrintf(ts, "CropWindow %f %f %f %f\n", cropMinX, cropMaxX, cropMinY, cropMaxY); 
  3549.   }
  3550.   // then feed the rib code to the stream and
  3551.   [self copyRIBCode:ts];
  3552.   // save the stream to the file selected in the savepanel
  3553.   NXSaveToFile(ts, filename);
  3554.  
  3555.   // and close the stream (which also flushes it), also making sure
  3556.   // that the allocated memory is freed.
  3557.   NXCloseMemory(ts,NX_FREEBUFFER);
  3558.  
  3559.   if (statusText) // potentially record activity
  3560.   {  sprintf(statusBuf, "done!");
  3561.      [statusText setStringValue:statusBuf];
  3562.   }
  3563.   return self;
  3564. }
  3565.  
  3566.  
  3567. - dumpRIBToFile:(char *)filename { return [self dumpRIBToFile:filename usingShadingRate:shadingRate hider:"hidden" pixelSamples:2 :2]; }
  3568.  
  3569.  
  3570. // when the well gets resized, I have to catch this and tell
  3571. // theRotator about it, cause the default doesn't seem to do it (cause it
  3572. // ain't a subview, natch)...
  3573. - sizeTo:(NXCoord)deltaWidth :(NXCoord)deltaHeight
  3574. {
  3575.   NXPoint  aPoint;
  3576.   float    radius;
  3577.  
  3578.  
  3579.   [super sizeTo:deltaWidth :deltaHeight];
  3580.  
  3581.   if (deltaWidth > deltaHeight)
  3582.   {  radius = deltaHeight / 2.0;
  3583.   }
  3584.   else
  3585.   {  radius = deltaWidth / 2.0;
  3586.   }
  3587.   aPoint.x = deltaWidth/2.0;
  3588.   aPoint.y = deltaHeight/2.0;
  3589.  
  3590.   [theRotator setCenter:&aPoint andRadius:radius];
  3591.  
  3592.   return self;
  3593. }
  3594.  
  3595. - setImageFile:(const char *)filename 
  3596. {
  3597.     // It's actually a bad idea to free this image, because it might be shared...
  3598.     // in this case, screw it, cause this has a very specific use...
  3599.    if (filename && *filename)
  3600.    {  image = [NXImage findImageNamed:filename];
  3601.       if (!image) 
  3602.       {  image = [[NXImage alloc] init];
  3603.          [image setDataRetained:YES];
  3604.          if (![image loadFromFile:filename])
  3605.          {  [self setImage:nil];
  3606.             NXLogError("unable to load image from file <%s>\n", filename);
  3607.             return nil; 
  3608.          }
  3609.       }
  3610.    }
  3611.    else
  3612.    {  [self setImage:nil];
  3613.       return nil;
  3614.    }
  3615.  
  3616.    return self;
  3617. }
  3618.  
  3619. - setImage:i  
  3620. {  //if (image) 
  3621.    //{ [image free]; 
  3622.    //} 
  3623.    image = i; 
  3624.    return self; 
  3625. }
  3626.  
  3627. #define SIZE    1
  3628. static float pattern[SIZE] = {2.};
  3629. static float offset = 0;
  3630.  
  3631. - drawPS:(NXRect *)rects :(int)nRects
  3632. {
  3633.   NXPoint p = {0.0, 0.0};
  3634.   NXSize  s;
  3635.  
  3636.    if ((selectionRegion.size.width > selectionWidthEpsilon)||(selectionRegion.size.height > selectionHeightEpsilon))
  3637.    {  PSsetgray(NX_WHITE);
  3638.       PSsetlinewidth(0.0);
  3639.       PSsetdash(pattern,SIZE, offset);
  3640.       PSrectstroke(selectionRegion.origin.x, selectionRegion.origin.y,  
  3641.            selectionRegion.size.width, selectionRegion.size.height);
  3642.  
  3643.       p.x = ((selectionRegion.origin.x) > 0) ? (selectionRegion.origin.x):0;
  3644.       p.y = ((selectionRegion.origin.y) > 0) ? (selectionRegion.origin.y):0;
  3645.   }
  3646.  
  3647.   // there is a bug in 3.2 HP that gets tickled when you have a View
  3648.   // that is 32 bits deep and has qrman drawing into it.  Since I don't
  3649.   // *really* use the fact that there is an alpha component to this image
  3650.   // when I composite it in here, I'm going to punt on doing a "source over"
  3651.   // operation, and just copy it into the View.
  3652.  
  3653.   if (image)
  3654.   {  //NXSetColor(NX_COLORBLACK);
  3655.      //PSsetalpha(1.0);
  3656.      [image getSize:&s];
  3657.      PScompositerect(p.x, p.y, s.width, s.height, NX_COPY); // used to be PScompositerect(p.x, p.y, s.width, s.height, NX_SOVER);
  3658.      [image composite:NX_COPY toPoint:&p]; //used to be [image composite:NX_SOVER toPoint:&p];
  3659.   }
  3660.   return self;
  3661. }
  3662.  
  3663.  
  3664. // need to add timed entries if I'm still holding the modifier down
  3665. // when I exit the inner modal loop.  Use the velocity at exit to set the
  3666. // frequency of the timed entry...
  3667. // When I reenter the mouseDown loop, I should remove any outstanding timed entries.
  3668. // when doing a timed entry, I should record frame rate and display it on the status bar
  3669.  
  3670. - removeAnimateTE
  3671. {
  3672.   if (animateTE)
  3673.   {  DPSRemoveTimedEntry(animateTE);
  3674.      animateTE = 0;
  3675.      animateRotate = NO;
  3676.      // switch back to the N3D_SmoothSolids surface type
  3677.      [self setSurfaceTypeForAll:renderStyle chooseHider:YES];    
  3678.      RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, tesselationVector, RI_NULL);
  3679.   }
  3680.   return self;
  3681. }
  3682.  
  3683.  
  3684. - animateRotate
  3685. {
  3686.   [theRotator trackMouseFrom:&oldMouse to:&newMouse rotationMatrix:rmat andInverse:irmat];
  3687.   [worldShape concatTransformMatrix:rmat premultiply:YES];
  3688.   oldMouse.x =  newMouse.x;
  3689.   oldMouse.y = newMouse.y;
  3690.   newMouse.x += dMouse.x;
  3691.   newMouse.y += dMouse.y;
  3692.   // NXLogError("old == (%f, %f) new == (%f, %f)\n", oldMouse.x, oldMouse.y, newMouse.x, newMouse.y);
  3693.   return self;
  3694. }
  3695.  
  3696.  
  3697. - animateScale
  3698. {
  3699.   return self;
  3700. }
  3701.  
  3702.  
  3703. - animateTranslate
  3704. {
  3705.   return self;
  3706. }
  3707.  
  3708.  
  3709. - animateClick
  3710. {
  3711.   if (animateRotate) { [self animateRotate]; }
  3712.   if (animateScale) { [self animateScale]; }
  3713.   if (animateTranslate) { [self animateTranslate]; }
  3714.   [self display];
  3715.   return self;
  3716. }
  3717.  
  3718.  
  3719. void animateHandler(DPSTimedEntry teNumber, double now, void *userData)
  3720. {
  3721.   id  myObj = (id)userData;
  3722.  
  3723.   [myObj animateClick];
  3724.   return ;
  3725. }
  3726.  
  3727.  
  3728. - removeRenderTE
  3729. {
  3730.   if (renderTE)
  3731.   {  DPSRemoveTimedEntry(renderTE);
  3732.      renderTE = 0;
  3733.      renderCount = 0;
  3734.      backgroundRendering = NO;
  3735.   }
  3736.   return self;
  3737. }
  3738.  
  3739.  
  3740. - setBackgroundRenderingOff  { [self removeRenderTE]; return self; }
  3741.  
  3742. - (BOOL)backgroundRendering { return backgroundRendering; }
  3743.  
  3744. - backgroundRender
  3745. {
  3746.   if (!backgroundRendering)
  3747.   {  renderCount++;
  3748.      if (renderCount == renderAtMediumRate)
  3749.      {  NXLogError("starting medium render...\n");
  3750.         backgroundRendering = YES;
  3751.         [delegate setRenderStartTime];
  3752.         [self renderAsTIFF];
  3753.      }
  3754.      if (renderCount == renderAtHighRate)
  3755.      {  NXLogError("starting high render...\n");
  3756.         backgroundRendering = YES;
  3757.         [delegate setRenderStartTime];
  3758.         [self renderAsTIFF];
  3759.      }
  3760.   }
  3761.   return self;
  3762. }
  3763.  
  3764.  
  3765. void renderHandler(DPSTimedEntry teNumber, double now, void *userData)
  3766. {
  3767.   id  myObj = (id)userData;
  3768.  
  3769.   [myObj backgroundRender];
  3770.   return ;
  3771. }
  3772.  
  3773.  
  3774. ////////////////////////////////////////////////////////////////////
  3775. //            So user can get some feedback
  3776. ///////////////////////////////////////////////////////////////////
  3777.  
  3778. static void getRegion(NXRect *region, const NXPoint *p1, const NXPoint  *p2)
  3779. /*
  3780.  * Returns the rectangle which has p1 and p2 as its corners.
  3781.  */
  3782. {
  3783.     region->size.width = p1->x - p2->x;
  3784.     region->size.height = p1->y - p2->y;
  3785.     if (region->size.width < 0.0) {
  3786.     region->origin.x = p2->x + region->size.width;
  3787.     region->size.width = ABS(region->size.width);
  3788.     } else {
  3789.     region->origin.x = p2->x;
  3790.     }
  3791.     if (region->size.height < 0.0) {
  3792.     region->origin.y = p2->y + region->size.height;
  3793.     region->size.height = ABS(region->size.height);
  3794.     } else {
  3795.     region->origin.y = p2->y;
  3796.     }
  3797. }
  3798.  
  3799.  
  3800. #define ACTIVEBUTTONMASK (NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK|NX_ALTERNATEMASK|NX_CONTROLMASK|NX_COMMANDMASK)
  3801. - mouseDown:(NXEvent *)theEvent
  3802. {
  3803.   int        oldMask;
  3804.   //NXPoint    p, last, start;
  3805.   //NXRect     visibleRect, oldRegion;
  3806.   NXPoint    start;
  3807.   RtPoint    myEyePoint, 
  3808.              previousEyePoint, previousViewPoint;
  3809.   float      previousRoll;
  3810.  
  3811.  
  3812.   [self removeAnimateTE];
  3813.   [self removeRenderTE];
  3814.   if (image)
  3815.   {  [image free];
  3816.      image = nil;
  3817.   }
  3818.  
  3819.   dMouse.x = 0.0;
  3820.   dMouse.y = 0.0;
  3821.  
  3822.   // track the mouse until a mouseUp event occurs, updating the display
  3823.   // as tracking happens.
  3824.   [self lockFocus];
  3825.   oldMask = [window addToEventMask:ACTIVEBUTTONMASK];
  3826.   
  3827.   // switch to the N3D_WireFrame surface type
  3828.   [self setSurfaceTypeForAll:movingRenderStyle chooseHider:YES];    
  3829.   RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, lowRezTesselationVector, RI_NULL);
  3830.   
  3831.   oldMouse = theEvent->location;
  3832.   [self convertPoint:&oldMouse fromView:nil];
  3833.   start = oldMouse;
  3834.  
  3835.   // when the alt key is depressed, we scale the worldShape up or down, depending on mouse movement.
  3836.   // otherwise, we rotate the worldShape using the virtual trackball
  3837.  
  3838.   while (1)
  3839.   { newMouse = theEvent->location;
  3840.     [self convertPoint:&newMouse fromView:nil];
  3841.     dMouse.x = newMouse.x - oldMouse.x;
  3842.     dMouse.y = newMouse.y - oldMouse.y;
  3843.     if (dMouse.x != 0.0 || dMouse.y != 0.0) 
  3844.     {  if (theEvent->flags & NX_ALTERNATEMASK)
  3845.        {  switch (trackballAffects)
  3846.       {  case WW_TRACKBALL_WORLD_SHAPE:
  3847.                  sprintf(statusBuf, "translating world in Z by %f", (translateZFactor * dMouse.y));
  3848.                  [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  3849.          [worldShape translate:0.0 :0.0 :(translateZFactor * dMouse.y)];
  3850.          break;
  3851.          case WW_TRACKBALL_CURRENT_SHAPE:
  3852.                  sprintf(statusBuf, "translating %s in Z by %f", [currentShape shapeName], (translateZFactor * dMouse.y));
  3853.                  [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  3854.          [currentShape translate:0.0 :0.0 :(translateZFactor * dMouse.y)];
  3855.          break;
  3856.          case WW_TRACKBALL_CAMERA:
  3857.          // need to change Eye point
  3858.                  sprintf(statusBuf, "moving eye point in Z by %f", (translateZFactor * dMouse.y));
  3859.                  [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  3860.          [self moveEyeBy:0.0 :0.0 :(-1. * (translateZFactor * dMouse.y))];
  3861.          break;
  3862.       }
  3863.        }
  3864.        else
  3865.        {  if (theEvent->flags & NX_CONTROLMASK)
  3866.       {  // NOTE draw rubber band selection here
  3867.          getRegion(&selectionRegion, &newMouse, &start);
  3868.              [statusText setStringValue:"selecting crop region for rendering..."]; [statusText display]; NXPing();
  3869.          //NXInsetRect(&oldRegion, -1.0, -1.0);
  3870.          //oldRegion = selectionRegion;
  3871.          // last = p;
  3872.           }
  3873.           else
  3874.       {  if (theEvent->flags & NX_COMMANDMASK)
  3875.              {  switch (trackballAffects)
  3876.           {  case WW_TRACKBALL_WORLD_SHAPE:
  3877.                     sprintf(statusBuf, "translating world in X & Y by (%f, %f)", (translateXFactor * dMouse.x), (translateYFactor * dMouse.y));
  3878.                     [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  3879.             [worldShape translate:(translateXFactor * dMouse.x) 
  3880.                                          :(translateYFactor * dMouse.y) :0.0];
  3881.             break;
  3882.            case WW_TRACKBALL_CURRENT_SHAPE:
  3883.                     sprintf(statusBuf, "translating %s in X & Y by (%f, %f)", 
  3884.                             [currentShape shapeName], (translateXFactor * dMouse.x), (translateYFactor * dMouse.y));
  3885.                     [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  3886.             [currentShape translate:(translateXFactor * dMouse.x) 
  3887.                                            :(translateYFactor * dMouse.y) :0.0];
  3888.                     break;
  3889.               case WW_TRACKBALL_CAMERA:
  3890.                     sprintf(statusBuf, "moving eye in X & Y by (%f, %f)", (translateXFactor * dMouse.x), (translateYFactor * dMouse.y));
  3891.                     [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  3892.                     [self moveEyeBy:(-1. * (translateXFactor * dMouse.x)) 
  3893.                              :(-1. * (translateYFactor * dMouse.y)) :0.0];
  3894.             break;
  3895.             }
  3896.          }
  3897.              else
  3898.              {  [theRotator trackMouseFrom:&oldMouse to:&newMouse rotationMatrix:rmat andInverse:irmat];
  3899.                 switch (trackballAffects)
  3900.         {  case WW_TRACKBALL_WORLD_SHAPE:
  3901.                        sprintf(statusBuf, "rotating world...");
  3902.                        [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  3903.                [worldShape concatTransformMatrix:rmat premultiply:YES];
  3904.                        break;
  3905.            case WW_TRACKBALL_CAMERA:
  3906.                        sprintf(statusBuf, "rotating camera...");
  3907.                        [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  3908.                [self getEyeAt:&previousEyePoint toward:&previousViewPoint roll:&previousRoll];   
  3909.                        myEyePoint[0] = previousEyePoint[0] + (-1. * (translateXFactor * dMouse.x)); 
  3910.                        myEyePoint[1] = previousEyePoint[1] + (-1. * (translateYFactor * dMouse.y)); 
  3911.                        myEyePoint[2] = previousEyePoint[2];
  3912.                [self setEyeAt:myEyePoint toward:previousViewPoint roll:previousRoll];   
  3913.                        break;
  3914.            case WW_TRACKBALL_CURRENT_SHAPE:
  3915.                        sprintf(statusBuf, "rotating %s...", [currentShape shapeName]);
  3916.                        [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  3917.                [currentShape concatTransformMatrix:rmat premultiply:YES];
  3918.                        break;
  3919.         }
  3920.          } 
  3921.       }
  3922.        }
  3923.        [self display];
  3924.        NXPing();
  3925.     }
  3926.     theEvent = [NXApp getNextEvent:ACTIVEBUTTONMASK];
  3927.     if (theEvent->type == NX_MOUSEUP)
  3928.     {  break;
  3929.     }
  3930.     else
  3931.     {  oldMouse = newMouse;
  3932.     }
  3933.   }
  3934.   [statusText setStringValue:"done"]; [statusText display]; NXPing();
  3935.  
  3936.   // check to see if we should go off and render (need a minimum image size, like 16x16)...
  3937.  
  3938.   // check to see if we should keep rotating or scaling...
  3939.   // if mouse was moving significantly, keep going...
  3940.   if (((float)fabs((double)(dMouse.x)) > epsilon) || ((float)fabs((double)dMouse.y) > epsilon))
  3941.   {  // comment out for now...
  3942.      //animateTE = DPSAddTimedEntry(.002, (DPSTimedEntryProc)animateHandler, self, NX_BASETHRESHOLD);
  3943.      //animateRotate = YES;
  3944.      [self setSurfaceTypeForAll:renderStyle chooseHider:YES];    
  3945.      RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, tesselationVector, RI_NULL);
  3946.   }
  3947.   else
  3948.   {  animateTE = 0;
  3949.      animateRotate = NO;
  3950.      // switch back to the N3D_SmoothSolids surface type
  3951.      [self setSurfaceTypeForAll:renderStyle chooseHider:YES];    
  3952.      RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, tesselationVector, RI_NULL);
  3953.  
  3954.      //renderTE = DPSAddTimedEntry(renderCheckTimeSlice, (DPSTimedEntryProc)renderHandler, self, NX_BASETHRESHOLD);
  3955.   }
  3956.  
  3957.   [self display];
  3958.   [self unlockFocus];
  3959.   [window setEventMask:oldMask];
  3960.   [window flushWindow];
  3961.  
  3962.   return self;
  3963. }
  3964.  
  3965. - (BOOL)acceptsFirstResponder { return YES; }
  3966.  
  3967. - (BOOL)acceptsFirstMouse { return YES; }
  3968.  
  3969. - keyDown:(NXEvent *)theEvent
  3970. {
  3971. //  id  theCmd = nil;
  3972.  
  3973.  
  3974.   // what we want to be able to do is have a set of mappings from the
  3975.   // charCode to some piece of tcl code.
  3976.   // We also want to be able to have the tcl code be executed in either
  3977.   // the camera's interp or the shape interp...
  3978.   // we'll say that if the cmd key is held down, it goes to the camera,
  3979.   // otherwise we send it to the root shape's interp.
  3980.  
  3981.   // we should probably have a hash table which has two things:
  3982.   // the charCode and the tcl code that corresponds to it
  3983.   // if there isn't an entry, drop through...
  3984.  
  3985. //  if (theEvent->flags & NX_COMMANDMASK)  // the command key is being held down : camera!
  3986. //  {  theCmd = [self cameraCmdFromCharCode:theEvent->data.key.charCode];
  3987. //     if (theCmd)
  3988. //     {  [tclInterp globalEval:[theCmd str]];
  3989. //     }
  3990. //     [delegate controlsWereUpdated:self];
  3991. //     return self;
  3992. //  }
  3993. //  else // must want to talk to the model, I guess...
  3994. //  {  theCmd = [self modelCmdFromCharCode:theEvent->data.key.charCode];
  3995. //     if (theCmd)
  3996. //     {  [[rootShape tclInterp] globalEval:[theCmd str]];
  3997. //     }
  3998. //     [delegate controlsWereUpdated:self];
  3999. //     return self;
  4000. //  }
  4001.  
  4002.   return [super keyDown:theEvent];
  4003. }
  4004.  
  4005. - takeRenderWorldAsBox:sender { [worldShape setDrawAsBox:[sender intValue]]; return [self display]; }
  4006. - takeRenderCurrentAsBox:sender { [currentShape setDrawAsBox:[sender intValue]]; return [self display]; }
  4007. - takeWorldIsVisible:sender { [worldShape setVisible:[sender intValue]]; return [self display]; }
  4008. - takeCurrentIsVisible:sender { [currentShape setVisible:[sender intValue]]; return [self display]; }
  4009.  
  4010. - (BOOL)renderWorldAsBox { return [worldShape doesDrawAsBox]; }
  4011. - (BOOL)renderCurrentAsBox { return [currentShape doesDrawAsBox]; }
  4012. - (BOOL)worldIsVisible { return [worldShape isVisible]; }
  4013. - (BOOL)currentIsVisible { return [currentShape isVisible]; }
  4014.  
  4015. - (int)trackballAffects { return trackballAffects; }
  4016. - takeTrackballAffectsFromMatrix:sender
  4017. {
  4018.   int  newVal = [[sender selectedCell] tag];
  4019.  
  4020.  
  4021.   switch (newVal)
  4022.   {  case WW_TRACKBALL_WORLD_SHAPE:
  4023.      trackballAffects = newVal;
  4024.          [self setUsePreTransformMatrix:NO];
  4025.      break;
  4026.      case WW_TRACKBALL_CAMERA:
  4027.      // we assume that [self usesPreTransformMatrix] returns YES...
  4028.      trackballAffects = newVal;
  4029.          [self setUsePreTransformMatrix:YES];
  4030.       break;
  4031.      case WW_TRACKBALL_CURRENT_SHAPE:
  4032.      trackballAffects = newVal;
  4033.          [self setUsePreTransformMatrix:NO];
  4034.      break;
  4035.      default:
  4036.      NXLogError("%d is an invalid value for trackballAffects.\n", newVal);
  4037.      } 
  4038.  
  4039.  
  4040.   return self;
  4041. }
  4042.  
  4043. - (int)trackballXYZ 
  4044.   N3DAxis  theAxis  = [theRotator rotationAxis];
  4045.   int      theAxisInt = -1;
  4046.  
  4047.  
  4048.   if (theAxis == N3D_AllAxes) { theAxisInt = 0; }
  4049.  
  4050.   if (theAxis == N3D_XAxis) { theAxisInt = 1; }
  4051.   if (theAxis == N3D_YAxis) { theAxisInt = 2; }
  4052.   if (theAxis == N3D_ZAxis) { theAxisInt = 3; }
  4053.  
  4054.   if (theAxis == N3D_XYAxes) { theAxisInt = 4; }
  4055.   if (theAxis == N3D_XZAxes) { theAxisInt = 5; }
  4056.   if (theAxis == N3D_YZAxes) { theAxisInt = 6; }
  4057.  
  4058.   return theAxisInt;
  4059. }
  4060.  
  4061. - takeTrackballXYZFromMatrix:sender
  4062. {
  4063.   int  newVal = [[sender selectedCell] tag];
  4064.  
  4065.   switch (newVal)
  4066.   {  case 0:
  4067.      [theRotator setRotationAxis:N3D_AllAxes];
  4068.      break;
  4069.      case 1:
  4070.      [theRotator setRotationAxis:N3D_XAxis];
  4071.      break;
  4072.      case 2:
  4073.      [theRotator setRotationAxis:N3D_YAxis];
  4074.      break;
  4075.      case 3:
  4076.      [theRotator setRotationAxis:N3D_ZAxis];
  4077.      break;
  4078.      case 4:
  4079.      [theRotator setRotationAxis:N3D_XYAxes];
  4080.      break;
  4081.      case 5:
  4082.      [theRotator setRotationAxis:N3D_XZAxes];
  4083.      break;
  4084.      case 6:
  4085.      [theRotator setRotationAxis:N3D_YZAxes];
  4086.      break;
  4087.      default:
  4088.      NXLogError("%d is an invalid value for trackballXYZ.\n", newVal);
  4089.      } 
  4090.   return self;
  4091. }
  4092.  
  4093.  
  4094. - tclInterp { return tclInterp; }
  4095.  
  4096.  
  4097. /// new camera stuff
  4098. - takeFocalLength:sender  {  return [self setFocalLength:[sender floatValue]];  }
  4099. - takeFocalDistance:sender {  return [self setFocalDistance:[sender floatValue]]; }
  4100. - takeFStop:sender {  return [self setFStop:[sender floatValue]]; }
  4101. - takeExposureLength:sender {  return [self setExposureLength:[sender floatValue]]; }
  4102.  
  4103. - takeShotOutputTypeFromMatrix:sender 
  4104. {  NXLogError("[WW3DCamera takeShotOutputTypeFromMatrix:sender] is not really implemented yet.\n");
  4105.    shotOutputType = [[sender selectedCell] tag]; 
  4106.    return self;
  4107. }
  4108.  
  4109. - takeShotLength:sender  {  return [self setShotLength:[sender floatValue]];  }
  4110. - takeFramesPerSecond:sender {  return [self setFramesPerSecond:[sender floatValue]]; }
  4111. - takeFrameNumber:sender {  return [self setFrameNumber:[sender intValue]]; }
  4112.  
  4113. - takeExposureLengthFactor:sender { return [self setExposureLengthFactor:[sender floatValue]]; }
  4114. - takeShotStartTime:sender  {  return [self setShotStartTime:[sender floatValue]];  }
  4115.  
  4116.  
  4117. - setRenderStyle:(int)s { renderStyle = s; [self setSurfaceTypeForAll:renderStyle chooseHider:YES]; [self display]; return self; }
  4118. - (int)renderStyle { return renderStyle; }
  4119.  
  4120. - setMovingRenderStyle:(int)s { movingRenderStyle = s; return self; }
  4121. - (int)movingRenderStyle { return movingRenderStyle; }
  4122.  
  4123. - (NXColor) backgroundColor     { return backgroundColor; }
  4124. - setBackgroundColor:(NXColor)c { backgroundColor = c; [self display]; return self; }
  4125.  
  4126. - (BOOL)showSelectedShape { return showSelectedShape; }
  4127. - setShowSelectedShape:(BOOL)flag 
  4128.    showSelectedShape = flag; 
  4129.    [currentShape setSelected:flag andDrawOrigin:drawOriginForSelectedShape];
  4130.    [self display];
  4131.    return self; 
  4132. }
  4133.  
  4134. - setSceneClock:newSceneClock { sceneClock = newSceneClock; return self; }
  4135. - sceneClock { return sceneClock; }
  4136.  
  4137. - (BOOL)drawOriginForSelectedShape { return drawOriginForSelectedShape; }
  4138. - setDrawOriginForSelectedShape:(BOOL)flag 
  4139.    drawOriginForSelectedShape = flag; 
  4140.    [currentShape setDrawOrigin:flag];
  4141.    [self display];
  4142.    return self; 
  4143. }
  4144.  
  4145. - otherLightList { return otherLightList; }
  4146.  
  4147. - addLocalLight:light usingPath:(const char *)aParentPath 
  4148.   id theLightParent = [[self worldShape] getChildGivenPath:aParentPath];
  4149.  
  4150.  
  4151.   if (theLightParent)
  4152.   {  [theLightParent addChild:light];
  4153.      [otherLightList addObject:light];
  4154.      return self;
  4155.   }
  4156.   return nil;
  4157. }
  4158.  
  4159. - setStatusText:newStatusText { statusText = newStatusText; return self; }
  4160. - statusText { return statusText; }
  4161.  
  4162. #define typeVectorVersion1 "i*ffffffff@[2f][2f]fiifcci@cffffffff@@@"
  4163. #define typeValuesVersion1 &renderStyle, &ribName, \
  4164.         &scaleUpFactor, &scaleDownFactor, &translateXFactor, &translateYFactor, &translateZFactor, \
  4165.         &epsilon, &selectionWidthEpsilon, &selectionHeightEpsilon, \
  4166.         &image, &lowRezTesselationVector, &tesselationVector, &shadingRate, \
  4167.         &renderAtMediumRate, &renderAtHighRate, &renderCheckTimeSlice, &showSelectedShape, &drawOriginForSelectedShape, \
  4168.         &movingRenderStyle, &tclInterp, &defaultLightsInUse, \
  4169.         &fStop, &focalLength, &focalDistance, &shutterOpenTime, &exposureLength, &frameTimeIncrement, &shotLength, &framesPerSecond, \
  4170.         &ambientLight, &leftLight, &rightLight
  4171.  
  4172.  
  4173. #define typeVectorVersion2 "i*ffffffff@[2f][2f]fiifcci@cffffffff@@@"
  4174. #define typeValuesVersion2 &renderStyle, &ribName, \
  4175.         &scaleUpFactor, &scaleDownFactor, &translateXFactor, &translateYFactor, &translateZFactor, \
  4176.         &epsilon, &selectionWidthEpsilon, &selectionHeightEpsilon, \
  4177.         &image, &lowRezTesselationVector, &tesselationVector, &shadingRate, \
  4178.         &renderAtMediumRate, &renderAtHighRate, &renderCheckTimeSlice, &showSelectedShape, &drawOriginForSelectedShape, \
  4179.         &movingRenderStyle, &tclInterp, &defaultLightsInUse, \
  4180.         &fStop, &focalLength, &focalDistance, &shutterOpenTime, &exposureLength, &frameTimeIncrement, &shotLength, &framesPerSecond, \
  4181.         &ambientLight, &leftLight, &rightLight
  4182.  
  4183.  
  4184. #define typeVectorVersion3 "i*ffffffff@fiifcci@cffffffff@@@"
  4185. #define typeValuesVersion3 &renderStyle, &ribName, \
  4186.         &scaleUpFactor, &scaleDownFactor, &translateXFactor, &translateYFactor, &translateZFactor, \
  4187.         &epsilon, &selectionWidthEpsilon, &selectionHeightEpsilon, \
  4188.         &image, &shadingRate, \
  4189.         &renderAtMediumRate, &renderAtHighRate, &renderCheckTimeSlice, &showSelectedShape, &drawOriginForSelectedShape, \
  4190.         &movingRenderStyle, &tclInterp, &defaultLightsInUse, \
  4191.         &fStop, &focalLength, &focalDistance, &shutterOpenTime, &exposureLength, &frameTimeIncrement, &shotLength, &framesPerSecond, \
  4192.         &ambientLight, &leftLight, &rightLight
  4193.  
  4194. #define typeVector "i*ffffffff@fiifcci@cffffffff@@@ff"
  4195. #define typeValues &renderStyle, &ribName, \
  4196.         &scaleUpFactor, &scaleDownFactor, &translateXFactor, &translateYFactor, &translateZFactor, \
  4197.         &epsilon, &selectionWidthEpsilon, &selectionHeightEpsilon, \
  4198.         &image, &shadingRate, \
  4199.         &renderAtMediumRate, &renderAtHighRate, &renderCheckTimeSlice, &showSelectedShape, &drawOriginForSelectedShape, \
  4200.         &movingRenderStyle, &tclInterp, &defaultLightsInUse, \
  4201.         &fStop, &focalLength, &focalDistance, &shutterOpenTime, &exposureLength, &frameTimeIncrement, &shotLength, &framesPerSecond, \
  4202.         &ambientLight, &leftLight, &rightLight, &shotStartTime, &exposureLengthFactor
  4203.  
  4204.  
  4205. - read:(NXTypedStream *)stream
  4206. {
  4207.     int version;
  4208.     
  4209.     [super read:stream];
  4210.     
  4211.     NX_DURING
  4212.     version = NXTypedStreamClassVersion(stream, "WW3DCamera");
  4213.     if (version == 0) NXReadTypes(stream,"i",&version), version=1;
  4214.     if (version == 1) {
  4215.         NXReadTypes(stream, typeVectorVersion1, typeValuesVersion1);
  4216.         backgroundColor = NXReadColor(stream);
  4217.         ribColor = NXReadColor(stream);
  4218.         shotStartTime = 0.0;
  4219.         exposureLengthFactor = 1.0;
  4220.     }
  4221.     if (version == 2) {
  4222.         NXReadTypes(stream, typeVectorVersion2, typeValuesVersion2);
  4223.         backgroundColor = NXReadColor(stream);
  4224.         ribColor = NXReadColor(stream);
  4225.         shotStartTime = 0.0;
  4226.         exposureLengthFactor = 1.0;
  4227.     }
  4228.     if (version == 3) {
  4229.         NXReadTypes(stream, typeVectorVersion3, typeValuesVersion3);
  4230.         NXReadArray(stream, "f", 2, lowRezTesselationVector);
  4231.         NXReadArray(stream, "f", 2, tesselationVector);
  4232.         backgroundColor = NXReadColor(stream);
  4233.         ribColor = NXReadColor(stream);
  4234.         sceneClock = NXReadObject(stream);
  4235.         shotStartTime = 0.0;
  4236.         exposureLengthFactor = 1.0;
  4237.     }
  4238.     if (version == 4) {
  4239.         NXReadTypes(stream, typeVector, typeValues);
  4240.         NXReadArray(stream, "f", 2, lowRezTesselationVector);
  4241.         NXReadArray(stream, "f", 2, tesselationVector);
  4242.         backgroundColor = NXReadColor(stream);
  4243.         ribColor = NXReadColor(stream);
  4244.         sceneClock = NXReadObject(stream);
  4245.     }
  4246.     NX_HANDLER
  4247.     NXLogError("in read: %s, exception [%d] raised.\n", [[self class] name], NXLocalHandler.code);
  4248.     return nil;
  4249.     NX_ENDHANDLER
  4250.     return self;
  4251. }
  4252.  
  4253. - write:(NXTypedStream *)stream 
  4254. {
  4255.     [super write:stream];
  4256.     exposureLength = savedExposureLength;  // just to make sure we archive it...
  4257.     NXWriteTypes(stream, typeVector, typeValues);
  4258.     NXWriteArray(stream, "f", 2, lowRezTesselationVector);
  4259.     NXWriteArray(stream, "f", 2, tesselationVector);
  4260.     NXWriteColor(stream, backgroundColor);
  4261.     NXWriteColor(stream, ribColor);
  4262.     NXWriteObjectReference(stream, sceneClock);
  4263.     return self;
  4264. }
  4265.  
  4266. @end
  4267.